AccordionItem component, that renders a <button>. The button updates the component and notifies its parent via the handleClick callback.isCollapsed prop in AccordionItem to determine its appearance and set its className.Accordion component. Use the useState() hook to initialize the value of the bindIndex state variable to defaultIndex.children to remove unnecessary nodes except for AccordionItem by identifying the function's name.Array.prototype.map() on the collected nodes to render the individual collapsible elements.changeItem, which will be executed when clicking an AccordionItem's <button>.changeItem executes the passed callback, onItemClick, and updates bindIndex based on the clicked element..accordion-item.collapsed { display: none; } .accordion-item.expanded { display: block; } .accordion-button { display: block; width: 100%; }
const AccordionItem = ({ label, isCollapsed, handleClick, children }) => {
return (
<>
<button className="accordion-button" onClick={handleClick}>
{label}
</button>
<div
className={`accordion-item ${isCollapsed ? 'collapsed' : 'expanded'}`}
aria-expanded={isCollapsed}
>
{children}
</div>
</>
);
};
const Accordion = ({ defaultIndex, onItemClick, children }) => {
const [bindIndex, setBindIndex] = React.useState(defaultIndex);
const changeItem = itemIndex => {
if (typeof onItemClick === 'function') onItemClick(itemIndex);
if (itemIndex !== bindIndex) setBindIndex(itemIndex);
};
const items = children.filter(item => item.type.name === 'AccordionItem');
return (
<>
{items.map(({ props }) => (
<AccordionItem
isCollapsed={bindIndex !== props.index}
label={props.label}
handleClick={() => changeItem(props.index)}
children={props.children}
/>
))}
</>
);
};
ReactDOM.render( <Accordion defaultIndex="1" onItemClick={console.log}> <AccordionItem label="A" index="1"> Lorem ipsum </AccordionItem> <AccordionItem label="B" index="2"> Dolor sit amet </AccordionItem> </Accordion>, document.getElementById('root') );
Subscribe to get resources directly to your inbox. You won't receive any spam! ✌️