Reputation: 404
I've mocked a simple logic for an accordion collapsible panels in ReactJS. I'm trying to allow for multiple collapsible to be open but I'm not able to avoid all the collapsible to open and close at once no matter which collapsible has been clicked. This below is the logic for the accordion to allow only one collapsible at the time.
//Accordion.js
import React, { useState } from "react";
import styled, { css } from "styled-components";
import PropTypes from "prop-types";
import Collapse from "./Collapse";
import Header from "./Header";
const Accordion = ({ list, icon}) => {
const [isActiveIndex, setActiveIndex] = useState(null);
const toggleItem = index => {
setActiveIndex(isActiveIndex === index ? null : index);
};
return (
<Wrapper>
{list.map((item, index) => {
const checkOpen = isActiveIndex === index;
return (
<Container key={index}>
<Header
title={item.title}
icon={icon}
id={index}
onClick={toggleItem}
/>
<Body isOpen={checkOpen}>
<Collapse isOpen={checkOpen}>{item.content}</Collapse>
</Body>
</Container>
);
})}
</Wrapper>
);
};
I've created the whole mock in CodeSandBox here: https://codesandbox.io/s/1r2mvk87q
For the initial accordion I'm using useState
and checking for the active index - for the allow multiple I guess I should check the previous state of the clicked item but I'm not able to pass the clicked item as the only target for the state to be checked.
//AccordionMultiple.js
const AccordionM = ({ list, icon }) => {
const [isOpen, setOpen] = useState(false);
const toggleItemM = index => {
setOpen(prevState => !prevState);
};
return (
<Wrapper>
{list.map((item, index) => {
return (
<Container key={index}>
<Header
title={item.title}
icon={icon}
id={index}
onClick={toggleItemM}
/>
<Body isOpen={isOpen}>
<Collapse isOpen={isOpen}>{item.content}</Collapse>
</Body>
</Container>
);
})}
</Wrapper>
);
};
Upvotes: 1
Views: 4283
Reputation: 282030
In order to allow for multiple collapsible column, you can make use of an object instead of a single index
const Accordion = ({ list, icon}) => {
const [isActivePanel, setActivePanel] = useState({});
const toggleItem = index => {
setActivePanel(prevState => ({...prevState, [index]: !Boolean(prevState[index])}));
};
return (
<Wrapper>
{list.map((item, index) => {
const checkOpen = isActivePanel[index];
return (
<Container key={index}>
<Header
title={item.title}
icon={icon}
id={index}
onClick={toggleItem}
/>
<Body isOpen={checkOpen}>
<Collapse isOpen={checkOpen}>{item.content}</Collapse>
</Body>
</Container>
);
})}
</Wrapper>
);
};
Upvotes: 2