Skip to content
shadcn.io
shadcn.io is not affiliated with official shadcn/ui

Shadcn Collapsible for React and Tailwind

Collapsible content in a vertical stack.

Total visits

22.3%10.1%6.8%1.4%

Installation

bunx --bun shadcn@latest add https://kit.dev/r/collapsible.json

For several labeled sections in one stack, use Accordion.

Anatomy

Collapsible
├── CollapsibleTrigger
│   └── CollapsibleIndicator
└── CollapsibleContent

useCollapsible is the machine hook for CollapsibleRootProvider. useCollapsibleContext / CollapsibleContext is in-tree.

Usage

import {
  Collapsible,
  CollapsibleContent,
  CollapsibleIndicator,
  CollapsibleTrigger,
} from "@/components/ui/collapsible";
<Collapsible>
  <CollapsibleTrigger asChild>
    <Button variant="outline">
      Details
      <CollapsibleIndicator />
    </Button>
  </CollapsibleTrigger>
  <CollapsibleContent>Hidden content</CollapsibleContent>
</Collapsible>

shadcn.io defaults lazyMount and unmountOnExit to true (Ark: false). Setting collapsedHeight (or relying on partial collapse) forces both off so the peek stays in the DOM.

className on CollapsibleContent is applied to an inner wrapper. Height animation uses --height / --collapsed-height on the content part.

Controlled

Use open and onOpenChange. { open } is a boolean.

Default open

Root Provider

Use useCollapsible with CollapsibleRootProvider when you need the API outside the tree. Pass lazyMount, unmountOnExit, collapsedHeight, and other machine options to useCollapsible(), not to the provider.

open is the intended state (changes immediately). visible stays true while the exit animation plays.

Context

States

Disabled

Examples

Nested

Partial collapse

collapsedHeight keeps a slice of the panel visible. Interactive controls inside the collapsed region are made inert so they cannot be focused.

Lazy mount

shadcn.io already sets lazyMount and unmountOnExit on the root. Content mounts on first open and leaves the DOM after the exit animation.

Guides

Open vs visible

PropertyMeaning
openIntended expanded state. Flips as soon as the trigger fires.
visibleContent is on screen, including during the close animation.

CSS variables

Set on the content part:

CSS variableDescription
--heightMeasured height when open
--widthMeasured width when open
--collapsed-heightPeek height from collapsedHeight
--collapsed-widthPeek width from collapsedWidth

Indicator

The default chevron rotates when data-state="open". Pass children to CollapsibleIndicator to replace it. Decorative icons should be aria-hidden.

API Reference

shadcn.io wraps Ark UI Collapsible. Defaults below are shadcn.io values. lazyMount and unmountOnExit default to true (Ark: false), except when collapsedHeight is set (both forced false).

asChild merges props onto a single child element.

Collapsible

Root. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseRender the child element instead of a div.
classNamestring-Class names on the root.
collapsedHeightstring | number-Height when closed (peek). Forces lazyMount and unmountOnExit off.
collapsedWidthstring | number-Width when closed.
defaultOpenbooleanfalseUncontrolled initial open state.
dir"ltr" | "rtl"-Text direction. Usually inherited from LocaleProvider.
disabledboolean-Disable the trigger.
hideMode"display-none" | "activity""display-none"How to hide mounted-but-closed content. activity needs React 19+.
idstring-Unique id for the machine.
idsPartial<{ root: string; content: string; trigger: string }>-Element ids for composition.
lazyMountbooleantrueMount content the first time it opens. Forced false with collapsedHeight.
onExitComplete() => void-Called when the close animation finishes.
onOpenChange(details: OpenChangeDetails) => void-Open state changed. { open: boolean }.
openboolean-Controlled open state.
unmountOnExitbooleantrueUnmount after the close animation. Forced false with collapsedHeight.
AttributeDescription
data-slotcollapsible
data-scopecollapsible
data-partroot
data-state"open" or "closed"
data-partial-collapsePresent when collapsedHeight is set (shadcn.io)

CollapsibleRootProvider

Takes the API from useCollapsible. Renders a div.

PropTypeDefaultDescription
valueUseCollapsibleReturnrequiredReturn value of useCollapsible().
asChildbooleanfalseRender the child element instead of a div.
classNamestring-Class names on the root.

Pass lazyMount, unmountOnExit, collapsedHeight, and other machine options to useCollapsible(), not to the provider.

CollapsibleTrigger

Toggles the panel. Renders a button. Use asChild with Button.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the trigger.
AttributeDescription
data-slotcollapsible-trigger
data-scopecollapsible
data-parttrigger
data-state"open" or "closed"
data-disabledPresent when disabled

aria-expanded follows visibility. aria-controls points at the content.

CollapsibleContent

The expanding panel. Renders a div. className is applied to an inner wrapper so height animation can use --height.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the inner wrapper.
AttributeDescription
data-slotcollapsible-content
data-scopecollapsible
data-partcontent
data-state"open" or "closed"
data-disabledPresent when disabled
data-has-collapsed-sizePresent when collapsedHeight or collapsedWidth is set
CSS variableDescription
--height / --widthMeasured open size
--collapsed-height / --collapsed-widthPeek size

CollapsibleIndicator

State-aware icon slot. Defaults to a chevron that rotates when open. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the indicator.
childrenReactNodechevronReplace the default icon.
AttributeDescription
data-slotcollapsible-indicator
data-scopecollapsible
data-partindicator
data-state"open" or "closed"
data-disabledPresent when disabled

useCollapsible

Creates the collapsible API for CollapsibleRootProvider. Accepts the same machine options as Collapsible except layout-only props (className, asChild). To match the shadcn.io root, pass lazyMount: true and unmountOnExit: true.

const collapsible = useCollapsible({ lazyMount: true, unmountOnExit: true });
collapsible.setOpen(true);

CollapsibleContext / useCollapsibleContext

Render-prop or hook access. Use inside Collapsible or CollapsibleRootProvider.

PropertyTypeDescription
openbooleanIntended expanded state.
visiblebooleanContent is on screen (including exit animation).
disabledbooleanWhether the collapsible is disabled.
setOpen(open: boolean) => voidOpen or close.
measureSize() => voidRe-measure content size.

CollapsibleContext children: (context) => ReactNode.

Accessibility

The trigger is a button with aria-expanded and aria-controls. Collapsed content is hidden from the tab order (inert when a collapsed size is set). Do not put the only copy of important actions solely inside a collapsed panel without a way to expand it from the keyboard.

Keyboard support

KeyDescription
TabMove to the trigger, then into open content.
Shift + TabMove to the previous control.
Enter / SpaceToggle the panel when the trigger is focused.