Components
Collapsible
An expandable/collapsible container for showing and hiding content.
Collapsible
The Collapsible component provides a way to show and hide content on demand. It's useful for FAQs, expandable sections, and progressive disclosure patterns where you want to reduce visual clutter.
For a more structured expand/collapse pattern with multiple items, consider using the Accordion component.
Features
- Controlled and uncontrolled modes
- Animated expand/collapse transitions
- Accessible trigger and content pairing
- Composable API with separate trigger and content components
- Supports custom trigger elements via
asChild
Usage
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from '@loke/design-system/collapsible';
export default function Example() {
return (
<Collapsible>
<CollapsibleTrigger>Toggle content</CollapsibleTrigger>
<CollapsibleContent>
<p>This content can be shown or hidden.</p>
</CollapsibleContent>
</Collapsible>
);
}Tips:
- Use
asChildonCollapsibleTriggerto use your own button component. - The
openandonOpenChangeprops enable controlled behavior. - Content is removed from the DOM when collapsed for performance.
Props
Collapsible
Prop
Type
CollapsibleTrigger
Prop
Type
CollapsibleContent
Prop
Type
Examples
Basic collapsible
@peduarte starred 3 repositories
@radix-ui/primitives
<Collapsible className="w-[350px] space-y-2">
<div className="flex items-center justify-between space-x-4">
<h4 className="text-sm font-semibold">
@peduarte starred 3 repositories
</h4>
<CollapsibleTrigger asChild>
<Button variant="ghost" size="sm">
<ChevronsUpDown className="h-4 w-4" />
</Button>
</CollapsibleTrigger>
</div>
<div className="rounded-md border px-4 py-3 font-mono text-sm">
@radix-ui/primitives
</div>
<CollapsibleContent className="space-y-2">
<div className="rounded-md border px-4 py-3 font-mono text-sm">
@radix-ui/colors
</div>
<div className="rounded-md border px-4 py-3 font-mono text-sm">
@stitches/react
</div>
</CollapsibleContent>
</Collapsible>Controlled collapsible
State: Closed
const [isOpen, setIsOpen] = useState(false);
<Collapsible open={isOpen} onOpenChange={setIsOpen}>
<CollapsibleTrigger asChild>
<Button variant="outline">
{isOpen ? 'Hide' : 'Show'} content
</Button>
</CollapsibleTrigger>
<CollapsibleContent>
<p className="mt-4">This content is controlled externally.</p>
</CollapsibleContent>
</Collapsible>Collapsible with animation
Expandable section
<Collapsible>
<CollapsibleTrigger asChild>
<Button variant="ghost" size="sm">
<ChevronsUpDown className="h-4 w-4" />
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="overflow-hidden data-[state=closed]:animate-collapse-up data-[state=open]:animate-collapse-down">
<p>Animated content</p>
</CollapsibleContent>
</Collapsible>Accessibility
- Trigger has
aria-expandedto indicate open/closed state. - Content is associated with trigger via
aria-controls. - Supports keyboard activation via Enter and Space keys.
- Content is hidden from screen readers when collapsed.
- Disabled state prevents interaction and is properly announced.
Best practices
- Use clear trigger text that indicates what will be revealed.
- Consider starting in an expanded state for critical content.
- Keep collapsed content relatively short to avoid jarring transitions.
- Use
forceMountwhen you need to measure content or animate with CSS. - Don't nest collapsibles too deeply — consider restructuring the UI.
- For multiple collapsible sections, consider using Accordion instead.