Collapsible
Show or hide a region of content with a controlled trigger — the primitive behind disclosures, FAQs, and inline expandables.
Trigger toggles aria-expanded and aria-controls; content stays in the DOM with hidden toggled so screen readers can re-announce it.
Preview
tsx
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ maxWidth: '24rem' }}>
<Collapsible>
<CollapsibleTrigger>Show more</CollapsibleTrigger>
<CollapsibleContent>
<p style={{ marginTop: '0.5rem' }}>
Collapsible regions are useful for progressive disclosure — keep the default view tight
and let users reveal extra detail on demand.
</p>
</CollapsibleContent>
</Collapsible>
</div>
);
}
Default open
Section titled “Default open”Pass defaultOpen to render the content expanded on first paint without controlling state yourself.
Preview
tsx
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ maxWidth: '24rem' }}>
<Collapsible defaultOpen>
<CollapsibleTrigger>Release notes</CollapsibleTrigger>
<CollapsibleContent>
<p style={{ marginTop: '0.5rem' }}>
Version 0.2.0 ships the new Calendar primitive, an overhauled colour picker, and tighter
focus rings across every interactive surface.
</p>
</CollapsibleContent>
</Collapsible>
</div>
);
}
Controlled
Section titled “Controlled”Pair open with onOpenChange to drive the state from the outside — handy when an external button or query param decides the open/close.
Preview
tsx
import {
Button,
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [open, setOpen] = useState(false);
return (
<div style={{ maxWidth: '24rem', display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
<div style={{ display: 'flex', gap: '0.5rem' }}>
<Button size="sm" variant="outline" onClick={() => setOpen(true)}>
Open
</Button>
<Button size="sm" variant="outline" onClick={() => setOpen(false)}>
Close
</Button>
</div>
<Collapsible open={open} onOpenChange={setOpen}>
<CollapsibleTrigger>Toggle inline</CollapsibleTrigger>
<CollapsibleContent>
<p style={{ marginTop: '0.5rem' }}>
The buttons above and the trigger below share the same state.
</p>
</CollapsibleContent>
</Collapsible>
</div>
);
}
Disabled
Section titled “Disabled”Pass disabled on Collapsible to freeze the current open state and prevent the trigger from firing.
Preview
tsx
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ maxWidth: '24rem' }}>
<Collapsible disabled>
<CollapsibleTrigger>Locked panel</CollapsibleTrigger>
<CollapsibleContent>
<p style={{ marginTop: '0.5rem' }}>
This content stays hidden — the trigger is disabled.
</p>
</CollapsibleContent>
</Collapsible>
</div>
);
}
PropTypeDefaultDescription
open
boolean
—
Controlled open state.
defaultOpen
boolean
—
Uncontrolled initial open state.
onOpenChange
((open: boolean) => void)
—
Fires with the next open state when toggled.
disabled
boolean
—
Disables the trigger and locks the panel in its current state.
Accessibility
Section titled “Accessibility”- The trigger sets
aria-expandedand pointsaria-controlsat the content region. - Content stays in the DOM with
hiddentoggled so assistive tech can re-announce it on every open. Enter/Spaceon the focused trigger toggles the panel.disabledpropagates to the underlying<button>and ARIA — keyboard users skip past it.- The trigger renders as a real
<button>(or yourasChildhost) so it inherits focus styles for free.
Recipes
Section titled “Recipes”- Use
asChildonCollapsibleTriggerto wrap aButtonand inherit Cynosure styling without losing the toggle behaviour. - Use
defaultOpenfor uncontrolled state; pairopen+onOpenChangeto control externally. - The
Disclosure/DisclosureTrigger/DisclosureContentaliases point at the same component when the semantic name fits better (e.g. FAQs). - Animate the open/close transition with the
data-state="open"anddata-state="closed"attributes onCollapsibleContent.