Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
In this article, we will make a simple accordion in react. Accordion is useful when we need to create some application user interactive. Basically, we will create a bunch of questions and if we click on the question, then the div will expand and show us the answer.
So this is going to be a very fun project to do and as a beginner it will teach us more because we will use some additional package like styled component. Also, we will make this accordion very dynamic like we can add question and answer in certain component and all effects will be reflected over the application. So let’s make it step-by-step.
Contents
Now firstly, we need to add two packages: (1) styled-components (2) react-icons.
Then we need some basic components like Accordion.js, where we will add main logic of the application. And Data.js component, where we will add questions and answer. We have to modify App component, here we imported Accordion, and we just called Accordion in return statement.
import './App.css';
import Accordion from './Components/Accordion';
function App() {
return <Accordion />;
}
export default App;
Now, before adding main logic, we will add our data like question and answer in Data component. We have added only three data and more data can be added which will reflect over the application.
export const Data = [
{
question: 'What do you call a dog magician?',
answer: 'A labracadabrador.'
},
{
question: 'What do you call a funny mountain?',
answer: 'Hill-arious.'
},
{
question: 'What did the astronaut say when he crashed into the moon?',
answer: 'I Apollo-gize.'
}
];
Now let’s move on to our main component, which is Accordion.js. Here we have imported our Data component to access the questions and answers from it. Then we have imported styled-components to do styling and basic CSS, with this we don’t need to add CSS in any other file. Then, we have imported react-icons to get access to icons like + and -, which will be useful in accordion list.
import React, { useState } from 'react';
import { Data } from './Data';
import styled from 'styled-components';
import { IconContext } from 'react-icons';
import { FiPlus, FiMinus } from 'react-icons/fi';
Now let’s move to return statement, here we used this Data.map()
method to fetch every data. Then we have added <Wrap> component which is actually created with styled component, which we will add some CSS in it. Here we have added a heading tag where we have fetched questions of every data. And then we added answers in paragraph.
const AccordionSection = styled.div`
`;
const Container = styled.div`
`;
const Wrap = styled.div`
`;
return (
<IconContext.Provider value={{ color: '#00FFB9', size: '25px' }}>
<AccordionSection>
<Container>
{Data.map((item, index) => {
return (
<>
<Wrap >
<h1>{item.question}</h1>
</Wrap>
<p>{item.answer}</p>
</>
);
})}
</Container>
</AccordionSection>
</IconContext.Provider>
);
};
Okay, we have fetched our data successfully, now we will add little CSS in styled components. Here we added common CSS as always, which you can simply modify to get your favorite effects. So here we did not do any special it’s like common CSS, so will move on another part of the logic.
const AccordionSection = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
height: 100vh;
background: #fff;
`;
const Container = styled.div`
position: absolute;
top: 30%;
box-shadow: 2px 10px 35px 1px rgba(153, 153, 153, 0.3);
`;
const Wrap = styled.div`
background: #272727;
color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
text-align: center;
cursor: pointer;
h1 {
padding: 2rem;
font-size: 2rem;
}
span {
margin-right: 1.5rem;
}
`;
const Dropdown = styled.div`
background: #1c1c1c;
color: #00ffb9;
width: 100%;
height: 100px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-bottom: 1px solid #00ffb9;
border-top: 1px solid #00ffb9;
p {
font-size: 2rem;
}
`;
Our question div is looking a little good, but now we need to hide the answer and show it on condition basis. For that, we have added a state named clicked with default false value. As we have a question in our Wrap component, we will add a click event where we will call the toggle function.
In this function, we have to check if index is equal to clicked which means question is already active then we just need to close it by updating clicked value with null. Otherwise, we will update the clicked value with the index value.
Also, we added a span in the Wrap component, where if clicked is equal to index then we will just put the minus icon, else we will replace the icon with a plus icon. Now for answer, we will put answer in a Dropdown component which will be visible if clicked is equal to index value. Otherwise, we won’t show answer.
const [clicked, setClicked] = useState(false);
const toggle = index => {
if (clicked === index) {
//if clicked question is already active, then close it
return setClicked(null);
}
setClicked(index);
};
return (
<IconContext.Provider value={{ color: '#00FFB9', size: '25px' }}>
<AccordionSection>
<Container>
{Data.map((item, index) => {
return (
<>
<Wrap onClick={() => toggle(index)} key={index}>
<h1>{item.question}</h1>
<span>{clicked === index ? <FiMinus /> : <FiPlus />}</span>
</Wrap>
{clicked === index ? (
<Dropdown>
<p>{item.answer}</p>
</Dropdown>
) : null}
</>
);
})}
</Container>
</AccordionSection>
</IconContext.Provider>
);
};
export default Accordion;
App.js
import './App.css';
import Accordion from './Components/Accordion';
function App() {
return <Accordion />;
}
export default App;
Accordion.js
import React, { useState } from 'react';
import { Data } from './Data';
import styled from 'styled-components';
import { IconContext } from 'react-icons';
import { FiPlus, FiMinus } from 'react-icons/fi';
const AccordionSection = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
height: 100vh;
background: #fff;
`;
const Container = styled.div`
position: absolute;
top: 30%;
box-shadow: 2px 10px 35px 1px rgba(153, 153, 153, 0.3);
`;
const Wrap = styled.div`
background: #272727;
color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
text-align: center;
cursor: pointer;
h1 {
padding: 2rem;
font-size: 2rem;
}
span {
margin-right: 1.5rem;
}
`;
const Dropdown = styled.div`
background: #1c1c1c;
color: #00ffb9;
width: 100%;
height: 100px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-bottom: 1px solid #00ffb9;
border-top: 1px solid #00ffb9;
p {
font-size: 2rem;
}
`;
const Accordion = () => {
const [clicked, setClicked] = useState(false);
const toggle = index => {
if (clicked === index) {
//if clicked question is already active, then close it
return setClicked(null);
}
setClicked(index);
};
return (
<IconContext.Provider value={{ color: '#00FFB9', size: '25px' }}>
<AccordionSection>
<Container>
{Data.map((item, index) => {
return (
<>
<Wrap onClick={() => toggle(index)} key={index}>
<h1>{item.question}</h1>
<span>{clicked === index ? <FiMinus /> : <FiPlus />}</span>
</Wrap>
{clicked === index ? (
<Dropdown>
<p>{item.answer}</p>
</Dropdown>
) : null}
</>
);
})}
</Container>
</AccordionSection>
</IconContext.Provider>
);
};
export default Accordion;
Data.js
export const Data = [
{
question: 'What do you call a dog magician?',
answer: 'A labracadabrador.'
},
{
question: 'What do you call a funny mountain?',
answer: 'Hill-arious.'
},
{
question: 'What did the astronaut say when he crashed into the moon?',
answer: 'I Apollo-gize.'
}
];
Check out awesome video of Accordion in React: