Collapsible
An interactive component which expands and collapses a panel, with an animated height and a trigger you supply.
- Status
- Since
0.1.0- Accessibility pattern
- APG disclosure
Last updated
Order 4189-B
Install
Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Collapsible before installation. Retain the digest printed by this command.
pnpm exec vegastack-design verify collapsibleInstall with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.
pnpm dlx shadcn@4.21.0 add @vegastack/collapsibleRun the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.
Usage
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
<Collapsible>
<CollapsibleTrigger>Can I use this in my project?</CollapsibleTrigger>
<CollapsibleContent>
Yes. Free to use for personal and commercial projects. No attribution
required.
</CollapsibleContent>
</Collapsible>;All three parts are unstyled pass-throughs, so the trigger is whatever you render into it — most
often a Button through render.
Order 4189-B
Anatomy
Examples
Composition
A trigger and the panel it reveals. The trigger carries aria-controls and aria-expanded; the
panel carries the id they name.
Collapsible
├── CollapsibleTrigger
└── CollapsibleContentControlled State
open and onOpenChange hand the state to the parent — which is what lets a second control, or the
trigger's own icon, read the same value.
const [open, setOpen] = React.useState(false);
<Collapsible open={open} onOpenChange={setOpen}>
<CollapsibleTrigger>Toggle</CollapsibleTrigger>
<CollapsibleContent>Content</CollapsibleContent>
</Collapsible>;State owned by the parent: false
Basic
Render the trigger as a full-width Button and let the panel own the surface. The trigger marks
itself data-panel-open while the panel is open, so group-data-panel-open/button:rotate-180 turns
the chevron without any state in your own component.
Settings Panel
A trigger beside a field group reveals the rest of the controls. The panel is a
grid-cols-subgrid cell, so the revealed fields land on the same columns as the ones above them.
File Tree
Collapsibles nest: each folder is its own root, and the panel holds the children — including more collapsibles. Nothing coordinates them, so each branch opens and closes on its own.
RTL
Wrap the subtree in DirectionProvider direction="rtl". The component itself adds no direction-aware
styling at all, so what flips is the content you render into it.
الطلب 4189-B
API Reference
Collapsible, CollapsibleTrigger and CollapsibleContent add no props of their own — each accepts
everything the corresponding Base UI Collapsible
part accepts (Root, Trigger, Panel): open / defaultOpen / onOpenChange and disabled on
the root, keepMounted and hiddenUntilFound on the panel, plus className, ref and render
everywhere.
Accessibility
- Renders Base UI's Collapsible: the trigger is a button carrying
aria-expandedand, while open,aria-controlspointing at the panel. - Enter and Space toggle the panel. The trigger stays
focusable while
disabled, so a keyboard user can still reach it and hear that it is unavailable. hiddenUntilFoundon the panel useshidden="until-found", which lets the browser's find-in-page reach the collapsed text and expand the panel around it.- Focus is the global 2px
:focus-visibleoutline frombase.css. The component contributes no focus styling of its own — whatever you render as the trigger brings its own. - The component renders no icon and no label. Give an icon-only trigger an accessible name.
| Contract | States tested |
|---|---|
| Behaviour | default, open, closed, disabled |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test, keyboard-navigation |
| Visual | inherited-from-call-site |
Do / Don't
Deviations
Upstream's file plus packages/ui/upstream/patches/collapsible.patch. Every hunk:
- NO STYLING HUNK AT ALL — upstream's Collapsible is three unstyled pass-throughs over Base UI
and imports no
cn, so nothing in it is ours to change. - DOC-1 — the whole diff is prettier's reflow plus the
registry-stamp.mjsprovenance header the three-copy model needs; no decision of its own.