Skip to content
Component installs need the registry setup
VegaStack Design

Collapsible

An interactive component which expands and collapses a panel, with an animated height and a trigger you supply.

Status
stable
Since
0.1.0
Accessibility pattern
APG disclosure

Last updated

Order 4189-B

StatusShipped

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 collapsible

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/collapsible

Run 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

StatusShipped

Anatomy

Collapsible — data-slot="collapsible"
CollapsibleContent — data-slot="collapsible-content"
CollapsibleTrigger — data-slot="collapsible-trigger"

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
└── CollapsibleContent

Controlled 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.

Radius
Set the corner radius of the element.

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-expanded and, while open, aria-controls pointing 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.
  • hiddenUntilFound on the panel uses hidden="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-visible outline from base.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.
ContractStates tested
Behaviourdefault, open, closed, disabled
Accessibilitynative-or-base-ui-semantics, browser-accessibility-test, keyboard-navigation
Visualinherited-from-call-site

Do / Don't

Do
Use a Collapsible for one optional region a reader opens deliberately — advanced settings, a details panel, a tree branch.
Don't
Use it to hide a form error, a required field, or anything the reader must act on.

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.mjs provenance header the three-copy model needs; no decision of its own.

On this page