snippetjavascriptTip
Collapsible content React components
Viewed 0 times
collapsiblecomponentsreactcontent
Problem
React makes collapsible content components a breeze with its state management and component composition. Simply put, you get full control over the content and its visibility, allowing you to create collapses, accordions, tabs and carousels.
For a simple collapsible content component, you need the
For accessibility purposes, it's a good idea to use the
<code-tabs full-width="true">
</code-tabs>
For a simple collapsible content component, you need the
useState() hook to manage the state of the collapsible content. Then, using a <button> to toggle the visibility of the content, you can make the content collapse or expand by changing the state.For accessibility purposes, it's a good idea to use the
aria-expanded attribute to indicate the state of the collapsible content.<code-tabs full-width="true">
</code-tabs>
Solution
const Collapse = ({ collapsed, children }) => {
const [isCollapsed, setIsCollapsed] = React.useState(collapsed);
return (
<>
<button
className="collapse-button"
onClick={() => setIsCollapsed(!isCollapsed)}
>
{isCollapsed ? 'Show' : 'Hide'} content
</button>
<div
className={`collapse-content ${isCollapsed ? 'collapsed' : 'expanded'}`}
aria-expanded={isCollapsed}
>
{children}
</div>
</>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<Collapse>
<h1>This is a collapse</h1>
<p>Hello world!</p>
</Collapse>
);For accessibility purposes, it's a good idea to use the
aria-expanded attribute to indicate the state of the collapsible content.<code-tabs full-width="true">
</code-tabs>
Accordions are very similar, but we need to manage the state a little differently, holding the index of the active accordion item. We can then toggle the visibility of the content based on the active index.
In order to make the component easier to read, we'll extract the
AccordionItem component to handle each accordion item. The Accordion component will manage the state and render the items.As an additional feature, we can pass a callback function to the
Accordion component to handle the click event on each accordion item. We may also want to filter out any non-AccordionItem children.Code Snippets
const Collapse = ({ collapsed, children }) => {
const [isCollapsed, setIsCollapsed] = React.useState(collapsed);
return (
<>
<button
className="collapse-button"
onClick={() => setIsCollapsed(!isCollapsed)}
>
{isCollapsed ? 'Show' : 'Hide'} content
</button>
<div
className={`collapse-content ${isCollapsed ? 'collapsed' : 'expanded'}`}
aria-expanded={isCollapsed}
>
{children}
</div>
</>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<Collapse>
<h1>This is a collapse</h1>
<p>Hello world!</p>
</Collapse>
);.collapse-button {
display: block;
width: 100%;
}
.collapse-content.collapsed {
display: none;
}
.collapsed-content.expanded {
display: block;
}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.createRoot(document.getElementById('root')).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>
);Context
From 30-seconds-of-code: collapsable-content-components
Revisions (0)
No revisions yet.