Collapsible
One region that opens under its trigger: show more, advanced settings, the log behind an error. No chrome of its own, a height tween on the system's motion tokens, and a mark that turns rather than swaps.
Installation#
Usage#
import {
Collapsible,
CollapsibleTrigger,
CollapsibleIcon,
CollapsibleContent,
} from "@/components/ui/collapsible"
export function Example() {
return (
<Collapsible>
<CollapsibleTrigger>
Advanced settings
<CollapsibleIcon />
</CollapsibleTrigger>
<CollapsibleContent>…</CollapsibleContent>
</Collapsible>
)
}Anatomy#
import {
Collapsible,
CollapsibleTrigger,
CollapsibleIcon,
CollapsibleContent,
} from "@/components/ui/collapsible"
<Collapsible>
<CollapsibleTrigger>
<CollapsibleIcon />
</CollapsibleTrigger>
<CollapsibleContent />
</Collapsible>The trigger#
On its own, CollapsibleTrigger is a quiet text control with the mark beside it, and its target grows to 40px without growing the text. With asChild it hands its behavior to your own control and keeps none of its look, which is how the Button above works: the Button stays a Button, and its label rolls while the caret turns.
Markers#
CollapsibleIcon turns with the trigger it sits in, on the same caret-turn beat as the height, so the mark and the region move as one gesture. marker picks the glyph and its turn: caret (the default) flips 180° for a panel below, branch turns 90° into a nested list, and plus turns 45° into a cross, the same mark Accordion and FAQ rows use.
Advanced settings#
The fields most people never touch, folded under the ones everyone fills in. Layout goes on CollapsibleContent's className: it styles the body, never the wrapper whose height is tweening, so the motion stays smooth.
Detail on demand#
Collapsible paints nothing, so it drops inside other components without a second frame. Here an Alert says what happened, and the log that says why stays folded until someone asks for it.
Motion#
The region's height tweens on the collapsible keyframes, retimed to duration-base and ease-out, and its body fades in with a 4px drop on the same clock, then out with a plain fade, softer than the way in. Content that renders open is never animated on page load: Radix skips the height, and the root holds the fade back until the state has changed once.
API reference#
Collapsible
The root, Radix Collapsible.Root: a plain <div> with no chrome that forwards all its props. Every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | - | Controlled open state. |
| defaultOpen | boolean | false | Initial open state when uncontrolled. |
| onOpenChange | (open: boolean) => void | - | Called when the region opens or closes. |
| disabled | boolean | false | Stops the trigger from toggling the region. |
| asChild | boolean | false | Merge onto your own element instead of rendering a <div>. |
| Data attribute | Description |
|---|---|
| data-state | "open" or "closed". |
| data-disabled | Present when disabled is set. |
CollapsibleTrigger
Radix Collapsible.Trigger, a <button> carrying aria-expanded and aria-controls; forwards all its props. Styled as a quiet text control with a 40px hit area unless asChild is set.
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | Hand the behavior to your own control (a Button, a row), which keeps its own look entirely. |
| Data attribute | Description |
|---|---|
| data-state | "open" or "closed"; the icon inside turns on it. |
| data-disabled | Present when the root is disabled. |
CollapsibleIcon
The decorative disclosure mark; it turns on the state of the trigger it sits in, so it must be inside CollapsibleTrigger (or its asChild element). Forwards all native <svg> props.
| Prop | Type | Default | Description |
|---|---|---|---|
| marker | "caret" | "branch" | "plus" | "caret" | The glyph and its turn: a caret flips 180°, a branch caret turns 90°, a plus turns 45° into a cross. |
CollapsibleContent
The region, Radix Collapsible.Content, unmounted once its close animation ends; forwards all its props. className styles the body inside the animated wrapper, so padding and layout go here without disturbing the height tween.
| Prop | Type | Default | Description |
|---|---|---|---|
| forceMount | true | - | Keep the region mounted while closed, for animating it with your own library. |
| Data attribute | Description |
|---|---|
| data-state | "open" or "closed". |
| data-disabled | Present when the root is disabled. |
| CSS variable | Description |
|---|---|
| --radix-collapsible-content-height | The region's measured height, read by the open and close tween. |
| --radix-collapsible-content-width | The region's measured width. |