Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to open the accordion for each item when click on icon?

I have created an accordion type component in reactjs In this When I open the first toggle, only toggle one content should open, when clicked on second toggle then the toggle one content should close and only toggle second content should be open(Only one toggle should be open at a time) . But in my case everytime same div is getting open. I don't know where I did wrong? and how to solve it?. below is my code

import React, { useState } from "react";
import { FaPlus, FaMinus } from "react-icons/fa";
import "./FAQ.scss";
import { Collapse } from "reactstrap";

const Question = (props) => {
    const [isOpen, setIsOpen] = useState(false);

    const toggle = () => setIsOpen(!isOpen);

    return (
        <div className="question">
            <div>
                <button onClick={toggle}>
                    {isOpen ? <FaMinus /> : <FaPlus />}
                </button>
            </div>
            <div onClick={toggle} className='title'>
                {props.question}
            </div>
                <Collapse isOpen={isOpen} className='content'>
                    The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for 
                    those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" 
                    by Cicero are also reproduced in their exact original form, accompanied by English 
                    versions from the 1914 translation by H. Rackham.
                </Collapse>
            <hr />
        </div>
    );
};

function FAQ() {
    return (
        <div className="faq" id='faq'>
            <h2>F.A.Q.</h2>
            <div className="faq-section">
                <Question question="Question one" />
                <Question question="Question two" />
                <Question question="Question three" />
                <Question question="Question four" />
                <Question question="Question five" />
            </div>
        </div>
    );
}

export default FAQ;

The screenshot is given in the below enter image description here

UPDATE THE QUESTION

Below is the link of a website the have the FAQ section in the bottom, I am trying to make the toggle feature as they have. FAQ section in the bottom of this website

like image 494
Inception_K Avatar asked Dec 06 '25 13:12

Inception_K


1 Answers

Issue

The issue here is that all Question components have their own state, independent of the others.

Solution

If you want to only open one Question at-a-time then the state needs to be lifted and declared in FAQ. This is so there's a single source of truth for what is opened/expanded.

FAQ

Move the isOpen state and toggle handler to this parent component. Use an "id" to toggle on/off the question component you want to expand. Pass an isOpen and toggle props to each Question component and handle the id logic here.

function FAQ() {
  const [isOpen, setIsOpen] = useState(null);

  const toggleOpen = id => () => setIsOpen(
    isOpen => isOpen === id ? null : id,
  );

  return (
    <div className="faq" id='faq'>
      <h2>F.A.Q.</h2>
      <div className="faq-section">
        <Question
          question="Question one"
          isOpen={isOpen === 0}
          toggle={toggleOpen(0)}
        />
        <Question
          question="Question two"
          isOpen={isOpen === 1}
          toggle={toggleOpen(1)}
        />
        <Question
          question="Question three"
          isOpen={isOpen === 2}
          toggle={toggleOpen(2)}
        />
        <Question
          question="Question four"
          isOpen={isOpen === 3}
          toggle={toggleOpen(3)}
        />
        <Question
          question="Question five"
          isOpen={isOpen === 4}
          toggle={toggleOpen(4)}
        />
      </div>
    </div>
  );
}

Question

Call/consume the isOpen and toggle from the passed props.

const Question = (props) => {
  return (
    <div className="question">
      <div>
        <button onClick={props.toggle}>
          {props.isOpen ? <FaMinus /> : <FaPlus />}
        </button>
      </div>
      <div onClick={props.toggle} className='title'>
        {props.question}
      </div>
      <Collapse isOpen={props.isOpen} className='content'>
        ....
      </Collapse>
      <hr />
    </div>
  );
};

Update

Ok, since it seems you are struggling with the issue of rendering the same "content" in each Question component I suggest you load up all your questions and content into an array and map them instead of hardcoding the JSX.

FAQ

const faqData = [
  {
    question: "Question one",
    content: <div> .... I'm content .... </div>, // <-- anything renderable as a child
  },
  ... etc...
];

function FAQ() {
  const [isOpen, setIsOpen] = useState(null);

  const toggleOpen = id => () => setIsOpen(
    isOpen => isOpen === id ? null : id,
  );

  return (
    <div className="faq" id='faq'>
      <h2>F.A.Q.</h2>
      <div className="faq-section">
        {faqData.map(({ content, question}, index) => (
          <Question
            key={index}
            content={content}
            question={question}
            isOpen={isOpen === index}
            toggle={toggleOpen(index)}
          />
        ))}
      </div>
    </div>
  );
}

Question

const Question = ({ content, question, isOpen, toggle }) => {
  return (
    <div className="question">
      <div>
        <button onClick={toggle}>
          {isOpen ? <FaMinus /> : <FaPlus />}
        </button>
      </div>
      <div onClick={toggle} className='title'>
        {question}
      </div>
      <Collapse isOpen={isOpen} className='content'>
        {content}
      </Collapse>
      <hr />
    </div>
  );
};

Edit how-to-open-the-accordion-for-each-item-when-click-on-icon

And just in case you missed it, you also need to import the bootstrap CSS somewhere in your project to get the bootstrap styles, transitions, and animations working.

import "bootstrap/dist/css/bootstrap.min.css";
like image 86
Drew Reese Avatar answered Dec 10 '25 12:12

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!