Collapse
The Collapse component provides smooth expand and collapse animations for showing and hiding content. It’s commonly used for nested menus, expandable sections, and progressive disclosure patterns.
Installation
npm install @naturacosmeticos/natds-web
import { Collapse, Button } from '@naturacosmeticos/natds-web';
import { useState } from 'react';
function BasicCollapse() {
const [open, setOpen] = useState(false);
return (
<div>
<Button onClick={() => setOpen(!open)}>
{open ? 'Hide' : 'Show'} Content
</Button>
<Collapse in={open}>
<div>
This content will smoothly expand and collapse
</div>
</Collapse>
</div>
);
}
Collapse Variants
Basic Collapse
Simple show/hide behavior:
function SimpleCollapse() {
const [checked, setChecked] = useState(false);
return (
<div>
<Button onClick={() => setChecked(!checked)}>
Toggle Content
</Button>
<Collapse in={checked}>
<div style={{ padding: 16 }}>
Collapsed content appears here
</div>
</Collapse>
</div>
);
}
With Nested List
Use Collapse with List components:
import { Collapse, List, ListItem, ListItemText } from '@naturacosmeticos/natds-web';
function CollapsibleList() {
const [open, setOpen] = useState(true);
return (
<List>
<ListItem button onClick={() => setOpen(!open)}>
<ListItemText primary="Inbox" />
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List disablePadding>
<ListItem>
<ListItemText primary="Starred" />
</ListItem>
<ListItem>
<ListItemText primary="Drafts" />
</ListItem>
</List>
</Collapse>
</List>
);
}
Auto Duration
Automatically calculate transition time based on height:
<Collapse in={open} timeout="auto">
<div>
Content with automatic transition duration based on content height
</div>
</Collapse>
Custom Duration
Specify custom enter and exit durations:
<Collapse
in={open}
timeout={{ enter: 500, exit: 300 }}
>
<div>
Content with custom transition timing
</div>
</Collapse>
Unmount On Exit
Remove content from DOM when collapsed:
<Collapse in={open} unmountOnExit>
<div>
This content is removed from DOM when collapsed
</div>
</Collapse>
Custom Collapsed Height
Set a minimum height when collapsed:
<Collapse
in={open}
collapsedHeight="40px"
>
<div style={{ height: 200 }}>
When collapsed, this maintains a 40px height
</div>
</Collapse>
Multiple Sections
Manage multiple collapsible sections:
function MultipleCollapse() {
const [openSections, setOpenSections] = useState({});
const toggleSection = (section) => {
setOpenSections(prev => ({
...prev,
[section]: !prev[section]
}));
};
return (
<div>
<Button onClick={() => toggleSection('section1')}>
Section 1
</Button>
<Collapse in={openSections.section1}>
<div>Content for section 1</div>
</Collapse>
<Button onClick={() => toggleSection('section2')}>
Section 2
</Button>
<Collapse in={openSections.section2}>
<div>Content for section 2</div>
</Collapse>
<Button onClick={() => toggleSection('section3')}>
Section 3
</Button>
<Collapse in={openSections.section3}>
<div>Content for section 3</div>
</Collapse>
</div>
);
}
With Card
Collapsible card content:
import { Card, CardContent, CardActions, Button } from '@naturacosmeticos/natds-web';
function CollapsibleCard() {
const [expanded, setExpanded] = useState(false);
return (
<Card>
<CardContent>
<Typography variant="h5">Card Title</Typography>
<Typography variant="body2">
Preview text that's always visible
</Typography>
</CardContent>
<CardActions>
<Button onClick={() => setExpanded(!expanded)}>
{expanded ? 'Show Less' : 'Show More'}
</Button>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography paragraph>
Additional content that can be expanded and collapsed.
This could include more details, specifications, or any other information.
</Typography>
</CardContent>
</Collapse>
</Card>
);
}
Nested Collapse
function NestedCollapse() {
const [level1, setLevel1] = useState(false);
const [level2, setLevel2] = useState(false);
return (
<div>
<Button onClick={() => setLevel1(!level1)}>
Level 1
</Button>
<Collapse in={level1}>
<div style={{ paddingLeft: 20 }}>
<p>Level 1 content</p>
<Button onClick={() => setLevel2(!level2)}>
Level 2
</Button>
<Collapse in={level2}>
<div style={{ paddingLeft: 20 }}>
<p>Level 2 content</p>
</div>
</Collapse>
</div>
</Collapse>
</div>
);
}
The content to be collapsed or expanded.
If true, the component will transition in and display the content.
timeout
number | { enter?: number, exit?: number } | 'auto'
The duration for the transition in milliseconds. You may specify a single timeout for all transitions, or individually with an object. Set to 'auto' to automatically calculate transition time based on height. Defaults to duration.standard.
collapsedHeight
string | number
default:"'0px'"
The height of the container when collapsed.
The component used for the root node. Either a string to use a DOM element or a component.
If true, the component will unmount when collapsed, removing it from the DOM.
Callback fired before the component enters.
Callback fired when the component is entering.
Callback fired when the component has entered.
Callback fired before the component exits.
Callback fired when the component is exiting.
Callback fired when the component has exited.
Best Practices
- Use
timeout="auto" for variable-height content
- Add
unmountOnExit to remove content from DOM when not visible
- Provide clear visual indicators (buttons, icons) for toggle interaction
- Consider using
collapsedHeight instead of complete hiding for preview content
- Avoid deeply nested collapses as they can be confusing
- Use consistent animation timing across your application
Performance Tips
- Use
unmountOnExit for heavy content to improve performance
- Consider lazy loading content that’s initially hidden
- Avoid animating large DOM trees
- Use CSS transforms when possible for smoother animations
Accessibility
- Ensure toggle buttons have clear labels
- Use ARIA attributes to indicate expanded/collapsed state
- Make sure collapsed content is not focusable when hidden
- Provide keyboard navigation support
- Consider using
aria-expanded on trigger elements
Common Patterns
FAQ Section
const faqs = [
{ question: 'What is this?', answer: 'Answer 1' },
{ question: 'How does it work?', answer: 'Answer 2' },
];
function FAQ() {
const [openIndex, setOpenIndex] = useState(null);
return (
<div>
{faqs.map((faq, index) => (
<div key={index}>
<Button onClick={() => setOpenIndex(openIndex === index ? null : index)}>
{faq.question}
</Button>
<Collapse in={openIndex === index}>
<div>{faq.answer}</div>
</Collapse>
</div>
))}
</div>
);
}
Related Components
- ExpansionPanel - For structured expandable panels
- Accordion - For grouped expandable sections
- List - Often used with Collapse for nested navigation