Skip to main content

Command Palette

Search for a command to run...

Accordion App With React

This is how I created a simple accordion app with ReactJs

Updated
5 min read
Accordion App With React
U

I work as an AI data labeller in the automotive industry. But my goal is to become a professional Front-end web developer.

Let's get started.

As always, I first of all design my projects in Figma before I move to development. This way, I do not get confused. I know exactly how to structure the UI as that thinking has already been done and it's in front of me.

Here is what we are going to build.

If you look at the screenshot of the finished product above, you will see that we have the header and the accordions. In the accordion components, we have the topic, the question underneath it and the answer (what will be shown when the accordion is expanded).

Every one of these pieces is a separate component. I then returned the parent component (accordion) in the App.js to render the app.

I started by creating a file Accordion.jsx in my src directory. This is the file that has all the code for the project.

So let's start with each component in the UI.

function Accordion() {
    return (
        <div></div>
    )
}

For now, we are simply returning an empty div element.

The AccordionItem component.

function AccordionItem() {
    return (
        <div className="container">
            <AccordionQuestion/>
            <AccordionAnswer/>
        </div>
    )
}

Now let's create the two components we are returning here.

The AccordionQuestion component

function AccordionQuestion() {
    return (
        <div className="header">
            <h2>Lorem ipsum dolor sit amet.</h2>
            <div className="question">
                <p>Nam itaque cumque et consectetur magni</p>
                <span>+</span>
            </div>
        </div>
    )
}

The AccordionAnswer component

function AccordionAnswer() {
    return (
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. 
        Doloribus soluta molestias accusantium ut eveniet architecto 
        vero repellendus. Officiis, cupiditate necessitatibus.</p>
    )
}

It is always clean and neat for you to write your data in a separate file like JSON or even just a simple object and import it into your app. We have been typing the accordion content manually but that is not the optimal way to do it if we are going to have multiple components.

Let's create a utilities file and write our data in it instead.

We write the following object in the file.

export const accordionData = [
    {
        subject: 'Lorem ipsum dolor sit amet.',
        question: 'Nam itaque cumque et consectetur magni?',
        answer: `Lorem ipsum dolor sit amet, consectetur adipisicing elit. 
        Nobis perspiciatis recusandae placeat qui, accusamus molestias 
        voluptates cupiditate culpa quo? Magnam atque vero nemo 
        molestiae tenetur. Placeat vel quas quisquam amet doloremque 
        perferendis numquam ut. Hic aut qui alias molestiae at. 
        Aspernatur quam doloremque dolores blanditiis itaque veniam 
        perferendis voluptate repellendus.`
    },

    {
        subject: 'Lorem ipsum dolor sit amet.',
        question: 'Nam itaque cumque et consectetur magni?',
        answer: `Lorem ipsum dolor sit amet, consectetur adipisicing elit. 
        Nobis perspiciatis recusandae placeat qui, accusamus molestias 
        voluptates cupiditate culpa quo? Magnam atque vero nemo 
        molestiae tenetur. Placeat vel quas quisquam amet doloremque 
        perferendis numquam ut. Hic aut qui alias molestiae at. 
        Aspernatur quam doloremque dolores blanditiis itaque veniam 
        perferendis voluptate repellendus.`
    }
]

All we need to do now is to import the parent component (accordion) and the utilities file in the App component to render our static accordion.

import Accordion from "./Accordion";
import { accordionData } from "./Utilities";
import './Style.css'


function App() {
  const items = accordionData;

  return (
   <div>
      <Accordion 
        items={items}
      />
   </div>
  );
}

export default App;

As you can see. Here we created an items variable that points to the accordion data and passed it down to <Accordion />

We are done writing the UI. At this point, we have a static accordion component. It is best to always write the UI first before logic and event handlers.

Create logic and event handlers

We go back to our Accordion and create the state using useState hook and the event handler.

function Accordion({ items }) {
    const [activeIndex, setActiveIndex] = useState(null)

    function handleClick(index) {
        setActiveIndex(activeIndex === index ? null : index)
    }

    return(
        <div>
            <Heading />

            {items.map((item, index) => (
                <AccordionItem 
                    key={index}
                    item={item}
                    isActive={index === activeIndex}
                    onToggle={() => handleClick(index)}
                />
            ))}
        </div>
    )
}

I created the state variables [activeIndex, setActiveIndex] and the handleClick function to toggle the activeIndex that expands or collapses the accordion. If the clicked item is the currently active one, it sets activeIndex to null (collapsing the item), otherwise, it sets activeIndex to the index of the clicked item.

In the return statement, we are returning the <Heading /> of the app and we are also mapping over the array of AccordionItem components. Each AccordionItem receives the following props: key, item, isActive and onToggle.

function AccordionItem({ item, isActive, onToggle}) {
    const {subject, question, answer} = item

    return (

        <div className="container">
             <AccordionQuestion
                 subject={subject}
                 question={question}
                 onToggle={onToggle}
                 isActive={isActive}
             />
             <AccordionAnswer
                 answer={answer}
                 isActive={isActive}
             />
        </div>

    )
}

I used a destructuring assignment to get our subject, question and answer properties from the array of objects.

function AccordionItem({ item, isActive, onToggle}) {
    const {subject, question, answer} = item
function AccordionAnswer({ answer, isActive }) {
    return (
        <>
            {isActive && <p>{answer}</p>}
        </>
    )
}

function AccordionQuestion({ subject, question, onToggle, isActive}) {
    return (
        <div className="header">
                <h2>{subject}</h2>
            <div className="subtitle" onClick={onToggle}>
                <p>{question}</p>
                <span>{ isActive ? '-' : '+'}</span>
            </div>
        </div>
    )
}

In the AccordionAnswer we pass in the answer and isActive props. It conditionally renders the answer only if the item is active (isActive is true).

The AccordionQuestion renders the question and toggle button of an accordion item.

The complete code

The Accordion component

import { useState } from "react";

function AccordionAnswer({ answer, isActive }) {
    return (
        <>
            {isActive && <p>{answer}</p>}
        </>
    )
}

function AccordionQuestion({ subject, question, onToggle, isActive}) {
    return (
        <div className="header">
                <h2>{subject}</h2>
            <div className="subtitle" onClick={onToggle}>
                <p>{question}</p>
                <span>{ isActive ? '-' : '+'}</span>
            </div>
        </div>
    )
}

function Heading() {
    return (
        <h1 className="heading">Accordion</h1>
    )
  }

function AccordionItem({ item, isActive, onToggle}) {

    const {subject, question, answer} = item

    return (

        <div className="container">
             <AccordionQuestion
                 subject={subject}
                 question={question}
                 onToggle={onToggle}
                 isActive={isActive}
             />
             <AccordionAnswer
                 answer={answer}
                 isActive={isActive}
             />
        </div>

    )
}

function Accordion({ items }) {
    const [activeIndex, setActiveIndex] = useState(null)

    function handleClick(index) {
        setActiveIndex(activeIndex === index ? null : index)
    }

    return(
        <div>
            <Heading />

            {items.map((item, index) => (
                <AccordionItem 
                    key={index}
                    item={item}
                    isActive={index === activeIndex}
                    onToggle={() => handleClick(index)}
                />
            ))}
        </div>
    )
}

export default Accordion

The App component

import Accordion from "./Accordion";
import { accordionData } from "./Utilities";
import './Style.css'


function App() {

  const items = accordionData;

  return (
   <div>
      <Accordion 
        items={items}
      />
   </div>
  );
}

export default App;

And we are done.