Closing Accordions Automatically

Hello everyone!

I'm currently working on a NextJS project and facing an issue with my dynamic accordion component. I'm using typescript, and the problem lies in only one accordion being able to open at a time. How can I ensure that only the specific one clicked on is toggled?

Currently, if there is already an active accordion, it automatically closes the previous one when attempting to open a new one. I want users to be able to open as many accordions as they wish without forcing the others to close.

Below is the snippet of my code:

import React, { useState } from 'react'
import { FaChevronDown, FaChevronUp } from 'react-icons/fa';

const faqList = () => {
  const faqArr = [
    // FAQs data
  ];
  
  const [accordion, setActiveAccordion] = useState(-1);
  let toggleAccordion = (id: number) => {
    if (id === accordion) {
      setActiveAccordion(-1);
      return;
    }
    setActiveAccordion(id);
  }

  return (
 
    <>
      <div className='grid grid-cols-1 xl:grid-cols-2'>
        {
          faqArr.map((FAQ, id) => 
            <div key={id} onClick={() => toggleAccordion(id)} className='accordionWrapper'>
              <div className={accordion === id ? 'open' : ''}>
                <div className='accordionHead'>
                  <h6>{FAQ.faqQuestion}</h6>
                    { accordion === id ? (
                      <FaChevronUp />
                    ) : (
                      <FaChevronDown />
                    ) }
                </div>
              </div>
              <div className={accordion === id ? 'content open' : 'content'}>
                <p>{FAQ.answer}</p>
              </div>
            </div>)
        }
      </div>
    </>
  )
}

export default faqList

Answer №1

To ensure your accordion functions properly, it is important that the state is set as an array containing the indexes of active items. You can achieve this by creating a Item component to manage this functionality.

const Item = ({ isOpen, FAQ, onClick }) => {
    return (
        <div
            onClick={onClick}
            className="mt-2 mb-2 cursor-pointer gap-12 ease-in"
        >
            <div className={isOpen ? 'block' : ''}>
                <div className="relative z-auto m-2 flex justify-between rounded-xl border-2 bg-white pt-4 pr-6 pb-4 pl-6 text-black dark:border-white dark:bg-black dark:text-white">
                    <h6 className="self-center font-bold">{FAQ.faqQuestion}</h6>
                    {isOpen ? (
                        <FaChevronUp className="text-k-dGray dark:text-k-lGray self-center" />
                    ) : (
                        <FaChevronDown className="text-k-dGray dark:text-k-lGray self-center" />
                    )}
                </div>
            </div>
            <div className={isOpen ? 'block ease-in' : 'hidden ease-in'}>
                <p className="text-k-dGray dark:text-k-lGray border-[666] z-0 m-2 -mt-6 flex rounded-xl rounded-tl-none rounded-tr-none border-l-2 border-r-2 border-b-2 pt-8 pr-6 pb-4 pl-6">
                    {FAQ.answer}
                </p>
            </div>
        </div>
    );
};

You can then utilize this component within the faqList

const faqList = () => {
    const [accordion, setActiveAccordion] = useState([]);
    const toggleAccordion = (id: number) => {
        const newArray = accordion.includes(id) ? accordion.filter(i => i !== id) : [...accordion, id]
        setActiveAccordion(newArray)
    };

    return (
        <>
            <div className="grid grid-cols-1 xl:grid-cols-2">
                {faqArr.map((FAQ, id) => (
                    <Item
                        key={id}
                        FAQ={FAQ}
                        isOpen={accordion.includes(id)}
                        onClick={() => toggleAccordion(id)}
                    />
                ))}
            </div>
        </>
    );
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

how to navigate to a different page programmatically upon selecting an option in the side menu

ionic start mySideMenu sidemenu --v2 After creating a sidemenu using the code above, I implemented some login-logout functionality by storing user details in a localStorage variable named "userDetails". When clicking on the logout option from the sideme ...

What is the process for embedding a NextJS app within a different website?

I'm searching for alternative methods to embed a React/NextJS application within another application. Currently, my solution involves using an iframe and specifying the source as the execution of the React/Nextjs application. I've explored diff ...

Utilizing useContext data in conjunction with properties

When using useContext in a component page, I am able to successfully retrieve data through useContext within a property. customColorContext.js import { createContext, useEffect, useState, useContext } from 'react'; // creating the context objec ...

Tips on adding an item to an array with React hooks and TypeScript

I'm a beginner with a simple question, so please bear with me. I'm trying to understand how to add an Object to the state array when a form is submitted. Thank you for your help! interface newList { name: string; } const ListAdder = () => { ...

Accessing Child Properties in Parent Component using Typescript

New to the world of Typescript! Imagine having a component called TitleSubtitle that consists of both a Title and a Subtitle component. The Title component comes with props: interface TitleProps { text: string; } The Subtitle component also has props ...

What do you think about gulp-typescript and the latest @types typings for TypeScript?

I've added @types/jasmine as a development dependency. This is my gulp task for compiling TypeScript: gulp.task('compile:tests', ['compile:typescript', 'clean:tests'], function () { var project = ts.createProject(&a ...

After the "markerClick" event triggers in Angular2 SebmGoogleMapMarker, the view fails to update

I am dealing with an array structured like this: locations: marker[] = [ {id: '1', lat: 51.5239935252832, lng: 5.137663903579778, content: 'Kids Jungalow (5p)', iconUrl: 'img/marker.png'}, {id: '2&apos ...

Mastering objectFit with Next.js 13: Unleashing the Power of <Image>

Within the latest version of next/image documentation, specifically version 13.0.0, it indicates that certain props such as layout, objectFit, objectPosition, lazyBoundary, and lazyRoot have been removed. The documentation for fill in the next/image sect ...

Using Jasmine to simulate an if/else statement in Angular/Typescript unit testing

After making a minor change to an existing function, it has been flagged as new code during our quality checks. This means I need to create a unit test specifically for the new 4 lines of code. The challenge is that there was never a unit test in place for ...

The presence of a constructor in a component disrupts the connection between React and Redux in

I am facing an issue with the connect function from 'react-redux' in my Typescript class example. The error occurs at the last line and I'm struggling to understand why it's happening. The constructor is necessary for other parts of the ...

What impact does setting 'pathmatch: full' in Angular have on the application?

When the 'pathmatch' is set to 'full' and I try to delete it, the app no longer loads or runs properly. import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { H ...

Encountering a Credential Provider malfunction causing an Authentication Error

In my current project development, I am utilizing Next.js, Prisma, PostgreSQL, and Vercel for deployment. At this stage, I am focusing on establishing a credential provider. While the Google and GitHub providers are already operational and working efficien ...

Ways to pass styling properties to a nested component

I am working on a component that includes an input field: <mat-form-field appearance="standard"> <mat-label >{{label}}<span>*</span></mat-label> <input [type]="type" <span matSuffix>{{suffix} ...

Best Practices for Organizing Imports in Typescript to Prevent Declaration Conflicts

When working with TypeScript, errors will be properly triggered if trying to execute the following: import * as path from "path" let path = path.join("a", "b", "c") The reason for this error is that it causes a conflict with the local declaration of &ap ...

Watching videos is quite a time-consuming process due to the long loading times

I recently created a website at , and I am facing an issue with the homepage video taking too long to play. While it works fine on a PC, it seems to load very slowly on mobile browsers. Any suggestions on how I can improve its loading speed? <video cl ...

Successfully resolving the API without encountering any response errors, even after sending a response

Once the data is successfully saved in the database and the image upload is completed, I am attempting to send res.json. However, I keep encountering the error message API resolved without sending a response for /api/auth/registeration, this may result in ...

Securing PDF files in storage to restrict access to only authenticated users using Next.js

I'm in the process of creating a website with some confidential pages. My main aim is to allow users to download PDF files from these pages, but only if they are logged in. I'm wondering where would be the best place to store these PDF files so t ...

The Angular Progressive Web App functions properly in ng serve mode, but encounters issues when running with http-server

I'm developing a Progressive Web App (PWA) using Angular. Everything was functioning smoothly until out of nowhere, I started encountering a 404 Error whenever I tried to navigate to a new component while serving in dist/project with http-server. Surp ...

Can TypeORM create an entity for a many-to-many relationship that functions like ActiveRecord's join table concept?

Consider a scenario where there is a Guardian entity connected to a Student entity. The goal is to establish their many-to-many relationship in TypeORM by introducing a new entity called StudentGuardianRelationship. This intermediary entity serves the purp ...

Angular 6 - Accessing grandparent methods in grandchild components

I am in need of running the functions of the grandparent component: import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.cs ...