DEV Community

loading...
Cover image for A 10 Line React Accordion Using an HTML Tag!

A 10 Line React Accordion Using an HTML Tag!

Deepak Ahuja πŸ‘¨β€πŸ’»
Lifelong learner, Software Engineer. Not in Forbes 30 under 30.
・Updated on ・3 min read

I recently came across a use case in which I needed an accordion component in my react application. I had a few options like using Material UI, some open source components this and this.

In my use case set of accordion options were dynamic, and they themselves carry information whether they should be open or not by default from the parent.

I tried a few components but after a day or two, I always had to go back and remove the component or add some behavior myself. In most components, parents keep track of open sections and children themselves have to use some change handler to inform parent for changing open sections.

So, I created one myself with just a few lines of code and without using any 3rd party library.

Accordion

Let me introduce to you HTML's <detail> tag.
This tag carries in itself the on-demand show/hide feature which is the core of accordion. We will use a set of these to create our component and it will save us tens of lines of code to handle the opening and closing behavior ourselves. This can be used to create our interactive widget which will have an open prop that decides whether to show or hide the content. All of this being a no-JavaScript widget.

Helper link: detail tag

Note: The details tag is not supported in Internet Explorer.

There's one more tag that we will need i.e <summary>. This tag defines a heading that can be clicked to show or hide the content section. It also comes with a built-in toggling arrow which we can customize.

Here's how it looks:

details plus summary tag

The Accordion Component

function Accordion({ children: options }) {
  const toOpen = options.props.open ? true : null;
  return options.map(options => (
    <details open={toOpen}>{options}</details>
  ));
}

Two things to note here:

  1. Children carry property whether they want to be open or not. You can change it as peruse.
  2. In JSX, props compile to plain javascript object before they are used an attribute to plain HTML, hence we return null to disallow it from being added to HTML. A detailed explanation:

First of all, JSX is just a syntactic sugar for React.createElement. So, it may look like, but, in reality, you don't specify html attributes: in fact, you are always passing props.

For instance, the JSX code <input type="button" value="My button" /> is transpiled into React.createElement('input',{type:'button',value:'My Button'})…

It will be used like this:

<Accordion>
   ...Options
</Accordion>

The Option Component

This will be the content of each section in the accordion. It uses summary tag to show the label (heading) of the section which is clickable. It renders children which for each section without any javascript.

function Option({ label, children }) {
  return (
    <React.Fragment>
      <summary>
        {label}
      </summary>
      {children}
    </React.Fragment>
  );
}

I used it like this,

<Accordion>
 {this.getOptions(status)}
</Accordion>

Some code to get options list:

function getOptions(status) {
 // status decides which options to return with what open flag
return [
     ...moreOptions, 
     <Option label="heading" open={status === "status1"}>
        <Component1
          someProp={someProp}
         />
      </Option>
    ]

}

Here's the final output with some applied CSS.

Note: To disable the default icon in summary component:

 summary::-webkit-details-marker {
     display: none
 }

Now feel free to play around with it. It is often advisable not to download and keep 3rd party libraries for simple use cases, It took me 5 tries to decide that I can just do it in less than 10 lines of code for which I kept adding 3rd party components. Simple functionalities can often be extracted out and used independently.

Thanks for making it to the end of the post, you are awesome!
Please share it if you found it helpful or drop me a hello on twitter :)

Discussion (6)

Collapse
eavichay profile image
Avichay Eyal

So basically you say you need react to put html that has already the full functionality.

Collapse
dpkahuja profile image
Deepak Ahuja πŸ‘¨β€πŸ’» Author • Edited

Hi Avichay, thanks for reading!

We need some sort of state management which we don’t get in plain HTML. We won’t be able to generate dynamic content or wonderful components under summary, or decide which sections to open, if it wouldn’t have been with react ( or any other UI lib/fw)

But yes HTML CSS has been advanced a lot.

Collapse
eavichay profile image
Avichay Eyal

I'm not following. What has react got to do with state management? React is a component rendering library. State management librariea has nothing to do with react, they either integrate with it or not

Thread Thread
dpkahuja profile image
Deepak Ahuja πŸ‘¨β€πŸ’» Author

"State management" here means component remembers during each render "what" sections to show and what to hide. I am not talking about external state management libraries.
Here, it means maintaining what open sections are (my examples don't maintain a list of what all sections are open at a given time, because this is not needed for basic examples, but we can certainly add it, if you need to allow only one section open at a time or whatever)
What has react got to do with state management?
I suggest you give a read about why these libraries/fws came after jQuery. Also, in depth explanation on react
here
Also, react, angular, vue. They all have something to do with state management.
here

Collapse
stephensauceda profile image
Stephen Sauceda

This may give a person the functionality they're looking for but it's worth mentioning the semantic and accessibility issues this introduces.

Details / Summary Are Not [insert control here]
Why <details> is Not an Accordion

Collapse
dpkahuja profile image
Deepak Ahuja πŸ‘¨β€πŸ’» Author • Edited

Hi stephen!
Thanks for reading.

Oh i see! I didn’t considered this. I actually used a ally accordion component (3rd party) i guess third link in first paragraph of my article. It wasn’t a good fit.
I’ll take care of it when I create a public facing app. I read both the articles you share. :)

FELLOW SCROLLERS: please don’t use this combination on public facing apps.