Accordion App With React
This is how I created a simple accordion app with ReactJs

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.




