Create custom React js Accordion component

Introduction

Creating components in react can be tricky for beginners. I have done some of my projects in react and the scope of some of those projects are small, so using external components library can make the project comparatively heavy. Instead I decided to create my own components and use them. In this article i am going to show you guys how i create my own accordion component in React js.

Thought process

So before starting the development, I was thinking of the steps to proceed. I was thinking of how to go forward. so here are the basic steps of development i though of while i was creating this component.

  • create a tab structure which contains a title and content section.
  • when i click on title, the content below will expand.
  • when this happens any other section which is expanded will close simultaneously.

Basically, we will create an accordion class in which we will populate the tabs from the tab data recieved in an array.  Inorder to do that, we will further define a tab component which will show the tab title and tab content.

So let’s get started!!

Defining accordion class

First we will create the base accordion class which will be the react component as follows:

class Accordion extends React.Component {
constructor(props) {
super(props)
this.state = {
tabs: [
{
id: 1,
title: "tab 1",
content: "this is tab 1",
active: true
},
{
id: 2,
title: "tab 2",
content: "this is tab 2",
active: false
},
{
id: 3,
title: "tab 3",
content: "this is tab 3",
active:false
}
]
}
}
render() {
const tabsArray = this.state.tabs;
return (
<div>
<h2>Accordion:</h2>
<div id="accordion">
{
tabsArray.map((tab,index)=>{
return <Tab key={index} id={tab.id} title={tab.title} content={tab.content} active={tab.active} />
})
}
</div>
</div>
)
}
}
ReactDOM.render(<Accordion />, document.querySelector("#app"))
view raw accordion.js hosted with ❤ by GitHub

As you can see, I have looped through the tabs array and rendered a Tab component in which i am passing tab data. As you add this structure, you will get an error as the <Tab /> component is not defined. Let’s ,get to it and define out Tab component.

Defining tab component class

Now let’s define the Tab component in which we will render the tab title and tab conetent. Add the following :

class Tab extends React.Component{
render(){
return(
<div className="tab">
<div className="title flex jc-btwn">
<span>{this.props.title}</span>
<i className={this.props.active?"fas fa-minus" : "fas fa-plus"}></i>
</div>
<div className={this.props.active ? "content show" : "content hide"}>
{this.props.content}
</div>
</div>
)
}
}
view raw tab.js hosted with ❤ by GitHub

now the tab structure is ready , lets add some styling to the tabs so that it will have the look of an accordion. add the following scss :

#accordion{
margin-top: 20px;
}
.tab{
.title{
padding:10px;
background-color: #f4f4f4;
}
.content{
padding:10px;
border: 1px 0 1px 1px;
border-style: solid;
border-color: #f4f4f4;
}
}
.flex{
display:flex;
}
.show{
display:block;
}
.hide{
display:none;
}
.jc-btwn{
justify-content: space-between;
}
view raw accordion.scss hosted with ❤ by GitHub

At this point, the accordion component is ready and you will fint he following output:

Accordion structure output
Accordion structure output

But when you try and click on the tab , you will se that the accordion is not functional yet as the client method has not been defined and added yet. so let’s do that now.

Handling the functionality

Inorder to get the accordion working, when the user clicks on the tab title, the tab component should pass the data i.e which tab is currently active to its parent i.e the accordion component.

We need to add a method which will update the active tab status and based on that status the accordion will render accordingly.

add the method in accordion class as follows:

class Accordion extends React.Component {
constructor(props) {
...
this.handleTabClick = this.handleTabClick.bind(this);
this.updateTabs = this.updateTabs.bind(this);
}
updateTabs(id){
let tabs = this.state.tabs;
let newtabs = tabs.map((tab, index)=>{
if(tab.id == id){
if(tab.active == true){
tab.active = false;
}else{
tab.active = true;
}
}else{
tab.active = false;
}
return tab;
});
return newtabs;
}
handleTabClick(id){
this.setState({tabs: this.updateTabs(id)});
}
render() {
...
<div>
<h2>Accordion:</h2>
<div id="accordion">
{
tabsArray.map((tab,index)=>{
return <Tab key={index} id={tab.id} handleclick={this.handleTabClick} title={tab.title} content={tab.content} active={tab.active} />
})
}
</div>
</div>
)
}
}
view raw accordion.js hosted with ❤ by GitHub

Along with that add the click method in your tab class to tab title container as follows:

/* As you can see on click of the title i have added a function which executes the method
recieved through props from the accordion class, which return the active tab back to the accordion class */
class Tab extends React.Component{
render(){
return(
<div className="tab">
<div className="title flex jc-btwn" onClick={()=>{
this.props.handleclick(this.props.id)
}}>
<span>{this.props.title}</span>
<i className={this.props.active?"fas fa-minus" : "fas fa-plus"}></i>
</div>
<div className={this.props.active ? "content show" : "content hide"}>
{this.props.content}
</div>
</div>
)
}
}
view raw tab.js hosted with ❤ by GitHub

If all the steps are followed properly, you will find your accordion working as shown in the fiddle below:

Conclusion

I will be creating more components like this and share with you guys in the coming articles. If you have any doubts or any suggestions let me know in the comments section below.

228
228