Skip to the content
BooleanPress UI

Panel

Collapsible

Shows or hides one region of content from a button.

Import

import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@booleanpress/ui/collapsible"

Usage

A collapsible is a disclosure: one trigger shows and hides one region. For several regions where one opens at a time, use an accordion.

import { Button } from "@booleanpress/ui/button"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@booleanpress/ui/collapsible"

export function Advanced() {
  return (
    <Collapsible>
      <CollapsibleTrigger asChild>
        <Button variant="ghost">Advanced settings</Button>
      </CollapsibleTrigger>
      <CollapsibleContent>Port 587, STARTTLS</CollapsibleContent>
    </Collapsible>
  )
}

It is uncontrolled with defaultOpen, or controlled with open and onOpenChange. It draws nothing of its own: the trigger is a bare button unless you pass asChild and your own, and the content has no border or padding. When the content is closed it is removed from the page. forceMount on CollapsibleContent keeps it in the page while closed, still showing: it only sets data-state="closed", and hiding it is yours to do (data-[state=closed]:hidden), for example to animate it. The content's height is exposed as --radix-collapsible-content-height for your own animation.

Examples

Basic

A button toggles two extra rows below an always-visible one.

Controlled

open and onOpenChange keep the state outside, so the trigger text can follow it.

Disabled

A disabled collapsible keeps its state and ignores the trigger.

Accessibility

Semantics
The trigger is a button with aria-expanded and aria-controls pointing at the content. Both parts carry data-state (open or closed). Closed content is removed from the page, so aria-controls points at an id that exists only while it is open.
Labels
The trigger needs a name that stays true when the state changes ("Advanced settings"), or a changing name that says the action ("Hide details"), not both. An icon-only trigger needs an aria-label.
Focus
The trigger is a tab stop. Focus stays on it when the content opens or closes; the content's own controls follow it in the tab order.
Known limits
  • There is no built-in indicator: draw a chevron or change the label yourself, and do not rely on the icon alone, since the state is in aria-expanded.
  • Closed content is not in the page, so the browser's find-in-page does not see it, and a screen reader cannot reach it.

Keyboard

Keyboard
KeyBehaviour
SpaceOpens or closes the content, with the trigger focused.
EnterOpens or closes the content, with the trigger focused.

API

Collapsible

Renders Radix Collapsible.Root and passes it every other prop.

Collapsible props
PropTypeDefaultDescription
asChildboolean
defaultOpenbooleanWhether it starts open, when it controls itself.
disabledbooleanPrevents the trigger from changing the state.
onOpenChange((open: boolean) => void)Called with the new state when the trigger is activated.
openbooleanWhether the content is shown, when you control it. Pair it with onOpenChange.

CollapsibleTrigger

Renders Radix Collapsible.CollapsibleTrigger and passes it every other prop.

CollapsibleTrigger props
PropTypeDefaultDescription
asChildbooleanRender the child element, usually a Button, instead of a bare button.

CollapsibleContent

Renders Radix Collapsible.CollapsibleContent and passes it every other prop.

CollapsibleContent props
PropTypeDefaultDescription
asChildbooleanRender the child element instead.
forceMounttrueUsed to force mounting when more control is needed. Useful when controlling animation with React animation libraries.

Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.

Data attributes: data-slot="collapsible" (Collapsible), data-slot="collapsible-trigger" (CollapsibleTrigger), data-slot="collapsible-content" (CollapsibleContent).

Theming

The tokens its classes read. Change their values in your theme, and it follows.

Theme tokens
TokenUsed for