# How to Build Accordion In React From Scratch Without Using Any External Library

As you might be aware, there are many applications of accordions like displaying a list of FAQs, various menus and submenus, for displaying various locations of a particular company and so on.

So In this article, we'll see how to build an accordion in React completely from scratch in a step-by-step way without using any external library.

We will be using React Hooks syntax for building this application in React. So if you're new to React Hooks, check out my [Introduction to React Hooks](https://levelup.gitconnected.com/an-introduction-to-react-hooks-50281fd961fe?source=friends_link&sk=89baff89ec8bc637e7c13b7554904e54) article to learn the basics of Hooks.

You can see the live demo of the application [here](https://react-accordion-demo.netlify.app/).

So let's get started.

## Initial Project Setup

Create a new project using `create-react-app`

```javascript
npx create-react-app react-accordion-demo
```

Once the project is created, delete all files from the `src` folder and create `index.js`, `App.js`, and `styles.css` files inside the `src` folder. Also, create a new folder with the name `utils` inside the `src` folder.

Open `styles.css` file and add the contents from [here](https://github.com/myogeshchavan97/react-accordion-demo/blob/master/src/styles.css) inside it.

## How to Create the Initial Pages

Open `src/App.js` file and add the following content inside it:

```jsx
import React from 'react';

const App = () => {
  const accordionData = {
    title: 'Section 1',
    content: `Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis sapiente
      laborum cupiditate possimus labore, hic temporibus velit dicta earum
      suscipit commodi eum enim atque at? Et perspiciatis dolore iure
      voluptatem.`
  };

  const { title, content } = accordionData;

  return (
    <React.Fragment>
      <h1>React Accordion Demo</h1>
      <div className="accordion">
        <div className="accordion-item">
          <div className="accordion-title">
            <div>{title}</div>
            <div>+</div>
          </div>
          <div className="accordion-content">{content}</div>
        </div>
      </div>
    </React.Fragment>
  );
};

export default App;
```

Here, we're using `accordionData` object properties for displaying the accordion content.

For the `content` property we're using ES6 template literal syntax (``) so we can spread the content across multiple lines and we've used a dummy lorem ipsum text.

Now, open `src/index.js` file and add the following content inside it:

```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './styles.css';

ReactDOM.render(<App />, document.getElementById('root'));
```

Now, If you run the application using `yarn start` command from the terminal, you will see the following screen:

![Initial Accordion](https://gist.github.com/myogeshchavan97/98ae4f4ead57fde8d47fcf7641220b72/raw/92ab4961521a20180285b6fdf5179b6d17fbcdff/accordion_initial.png)

## How to Open and Close Accordion

As you can see above, we're displaying a single section as a part of the accordion but by default, the accordion is expanded and we can't close it. So let's add functionality to open and close the accordion.

Add a new state inside the component as shown below:

```js
const [isActive, setIsActive] = useState(false);
```

Here, we've defined `isActive` state and based on that, we'll hide or show the accordion content.

Also import the `useState` hook at the top of the file:

```js
import React, { useState } from 'react';
```

Now, for the `div` with class `accordion-title`, add the `onClick` handler like this:

```jsx
<div className="accordion">
  <div className="accordion-item">
    <div
      className="accordion-title"
      onClick={() => setIsActive(!isActive)}
    >
      <div>{title}</div>
      <div>{isActive ? '-' : '+'}</div>
    </div>
    {isActive && <div className="accordion-content">{content}</div>}
  </div>
</div>
```

Here, we're inverting the `isActive` state value when we click on the `accordion-title` div. If the value of `isActive` is `false`, we're setting it to `true` and vice-versa. 

We're also showing the `+` or `-` sign depending on the value of `isActive` using the ternary operator.

And If the `isActive` state value is `true` then only we're showing the accordion content as shown below:

```jsx
{isActive && <div className="accordion-content">{content}</div>}
```

Now, If you check the application, you will see the following screen:

![Open and close accordion](https://gist.github.com/myogeshchavan97/98ae4f4ead57fde8d47fcf7641220b72/raw/92ab4961521a20180285b6fdf5179b6d17fbcdff/open_close.gif)

As you can see, initially, the accordion is closed and on clicking on the title, the accordion opens and we can click on it again to close it.

## How to add Multiple Sections in Accordion

This is working fine for a single section of the accordion but If we have multiple sections, It will not be good to copy-paste the same JSX code again and again with different content.

So let's create a separate component to just display the accordion and based on the number of sections, we'll loop over the component to display multiple sections.

Create a new `Accordion.js` file inside the `src` folder and add the following contents inside it:

```jsx
import React, { useState } from 'react';

const Accordion = ({ title, content }) => {
  const [isActive, setIsActive] = useState(false);

  return (
    <div className="accordion-item">
      <div className="accordion-title" onClick={() => setIsActive(!isActive)}>
        <div>{title}</div>
        <div>{isActive ? '-' : '+'}</div>
      </div>
      {isActive && <div className="accordion-content">{content}</div>}
    </div>
  );
};

export default Accordion;
```

Here, we've moved the state and `accordion-item` div from the `App.js` file into `Accordion.js` file and we're passing the dynamic `title` and `content` props to the component using ES6 destructuring syntax like this:

```js
const Accordion = ({ title, content }) => {
```

Now, open `App.js` file and replace it with the following content:

```jsx
import React from 'react';
import Accordion from './Accordion';

const App = () => {
  const accordionData = [
    {
      title: 'Section 1',
      content: `Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis sapiente
      laborum cupiditate possimus labore, hic temporibus velit dicta earum
      suscipit commodi eum enim atque at? Et perspiciatis dolore iure
      voluptatem.`
    },
    {
      title: 'Section 2',
      content: `Lorem ipsum, dolor sit amet consectetur adipisicing elit. Mollitia veniam
      reprehenderit nam assumenda voluptatem ut. Ipsum eius dicta, officiis
      quaerat iure quos dolorum accusantium ducimus in illum vero commodi
      pariatur? Impedit autem esse nostrum quasi, fugiat a aut error cumque
      quidem maiores doloremque est numquam praesentium eos voluptatem amet!
      Repudiandae, mollitia id reprehenderit a ab odit!`
    },
    {
      title: 'Section 3',
      content: `Sapiente expedita hic obcaecati, laboriosam similique omnis architecto ducimus magnam accusantium corrupti
      quam sint dolore pariatur perspiciatis, necessitatibus rem vel dignissimos
      dolor ut sequi minus iste? Quas?`
    }
  ];

  return (
    <div>
      <h1>React Accordion Demo</h1>
      <div className="accordion">
        {accordionData.map(({ title, content }) => (
          <Accordion title={title} content={content} />
        ))}
      </div>
    </div>
  );
};

export default App;
```

Here, we've converted the `accordionData` from object to array of objects and we're looping over it using the array map method and passing the corresponding `title` and `content` to the `Accordion` component.

Now, If you check the application, you will see the three sections getting displayed and we can open and close each section as shown below:

![final working accordion](https://gist.github.com/myogeshchavan97/98ae4f4ead57fde8d47fcf7641220b72/raw/92ab4961521a20180285b6fdf5179b6d17fbcdff/final_working.gif)

## Code Refactoring

So as you can see, by just moving out the accordion section into a separate component and passing the dynamic content as props, we're successfully able to create a working version of an accordion from scratch. 

It's a better practice to keep the static data in a separate file. So let's move the `accordionData` array to a different file and import it into `App.js` file.

Create a new file `content.js` inside the `utils` folder and add the following contents inside it:

```js
export const accordionData = [
  {
    title: 'Section 1',
    content: `Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis sapiente
    laborum cupiditate possimus labore, hic temporibus velit dicta earum
    suscipit commodi eum enim atque at? Et perspiciatis dolore iure
    voluptatem.`
  },
  {
    title: 'Section 2',
    content: `Lorem ipsum, dolor sit amet consectetur adipisicing elit. Mollitia veniam
    reprehenderit nam assumenda voluptatem ut. Ipsum eius dicta, officiis
    quaerat iure quos dolorum accusantium ducimus in illum vero commodi
    pariatur? Impedit autem esse nostrum quasi, fugiat a aut error cumque
    quidem maiores doloremque est numquam praesentium eos voluptatem amet!
    Repudiandae, mollitia id reprehenderit a ab odit!`
  },
  {
    title: 'Section 3',
    content: `Sapiente expedita hic obcaecati, laboriosam similique omnis architecto ducimus magnam accusantium corrupti
    quam sint dolore pariatur perspiciatis, necessitatibus rem vel dignissimos
    dolor ut sequi minus iste? Quas?`
  }
];
```

Now, open `App.js` file and replace it with the following content:

```jsx
import React from 'react';
import Accordion from './Accordion';
import { accordionData } from './utils/content';

const App = () => {
  return (
    <div>
      <h1>React Accordion Demo</h1>
      <div className="accordion">
        {accordionData.map(({ title, content }) => (
          <Accordion title={title} content={content} />
        ))}
      </div>
    </div>
  );
};

export default App;
``` 

Here, we've just imported the static data from the external file and removed it from the `App.js` file.

So now, the code looks clean and easy to understand and the functionality is working as before.

![final working accordion](https://gist.github.com/myogeshchavan97/98ae4f4ead57fde8d47fcf7641220b72/raw/92ab4961521a20180285b6fdf5179b6d17fbcdff/final_working.gif)

## Closing points

We're done building out the functionality of the App.

**You can find the complete GitHub source code for this application in [this repository](https://github.com/myogeshchavan97/react-accordion-demo).**

### Thanks for reading!

Want to learn all ES6+ features in detail including let and const, promises, various promise methods, array and object destructuring, arrow functions, async/await, import and export and a whole lot more from scratch?

Check out my [Mastering Modern JavaScript](https://modernjavascript.yogeshchavan.dev/) book. This book covers all the pre-requisites for learning React and helps you to become better at JavaScript and React.

**Check out free preview contents of the book [here](https://www.freecodecamp.org/news/learn-modern-javascript/).**

Also, you can check out my free [Introduction to React Router](https://yogeshchavan.podia.com/react-router-introduction) course to learn React Router from scratch.

Want to stay up to date with regular content regarding JavaScript, React, Node.js? [Follow me on LinkedIn](https://www.linkedin.com/in/yogesh-chavan97/).

[<img src="https://gist.github.com/myogeshchavan97/98ae4f4ead57fde8d47fcf7641220b72/raw/92ab4961521a20180285b6fdf5179b6d17fbcdff/freecodecamp_image.jpeg">](https://modernjavascript.yogeshchavan.dev/)

[<img src="https://cdn.buymeacoffee.com/buttons/default-yellow.png" >](https://www.buymeacoffee.com/myogeshchavan97)
