Skip to content

Collapsible

Shows and hides a block of content from a trigger, like a record's details.

Library
What’s this?

Acme Corporation

Customer · Manufacturing

Installation

pnpm dlx shadcn@latest add @wisty/collapsible

The CLI installs the Radix or Base UI file to match your project.

If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.

When to use

Use it

  • A block of content is useful but not always needed, like an account's address and owner under its summary, as the Account details example shows.
  • People show and hide each section on its own, and opening one leaves the others as they are.
  • A section of a form people fold away, like advanced options.
  • You want an expandable section: a gray title bar with a chevron above content that folds away.

Don't use it

  • Several sections where opening one closes the others. Use Accordion.
  • Content that switches between peers, like related lists. Use Tabs.
  • A short hint or extra detail on demand. Use Popover or Tooltip.

Usage

Collapsible
├── CollapsibleTrigger
└── CollapsibleContent

Collapsible has no styles of its own. Style the trigger as a button with buttonVariants(), as the Account details example does, or build an expandable section: the trigger goes in a heading, and the chevron turns on the trigger's aria-[expanded=false].

import { ChevronDownIcon } from "lucide-react"

import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible"
<Collapsible defaultOpen>
  <h2 className="my-2 text-(length:--section-title-size) leading-[1.875rem]">
    <CollapsibleTrigger className="flex w-full items-center gap-2 rounded-(--radius-2) border border-transparent bg-muted px-2 text-start font-(--section-title-weight) text-foreground outline-none focus-visible:shadow-(--shadow-focus) aria-[expanded=false]:[&>svg]:-rotate-90 [&>svg]:size-3.5 [&>svg]:shrink-0">
      <ChevronDownIcon />
      System information
    </CollapsibleTrigger>
  </h2>
  <CollapsibleContent className="pt-2 text-muted-foreground">
    {/* section body */}
  </CollapsibleContent>
</Collapsible>

Closed content leaves the page, and with it any form state inside. In Base UI projects, pass keepMounted to CollapsibleContent to keep it there hidden, or hiddenUntilFound so find-in-page can find and open it. In Radix projects, forceMount keeps it there but also keeps it showing, so hide it yourself with data-[state=closed]:hidden.

API reference

SLDS mapping

Collapsible has no SLDS classes. The section in Usage builds SLDS's expandable section (slds-section): the heading is slds-section__title, the trigger slds-section__title-action, the chevron slds-section__title-action-icon, and the content slds-section__content. The Account details example uses a bare icon button (slds-button_icon-container) and bordered rows (slds-box).

Known gaps:

  • The section's chevron is lucide's ChevronDownIcon. SLDS uses its utility:switch caret.

Accessibility

  • Put a section's trigger inside a heading, at the level that follows the page's headings, so the section shows up in the outline.
  • An icon-only trigger needs an aria-label that says what it shows. Keep the chevron decorative.

Rules

  • Keep the chevron inside the trigger, so it turns with the trigger's aria-expanded.