---
title: Collapsible
description: An interactive component which expands/collapses a panel.
icon: minimize-2
author:
  name: imskyleen
  url: https://github.com/imskyleen
mode: wide
---

<PoweredBy
  packages={[
    { name: 'Base UI', url: 'https://base-ui.com/react/components/collapsible' },
    { name: 'Shadcn UI', url: 'https://ui.shadcn.com/docs/components/collapsible' },
  ]}
/>

### Installation

```package-install
npx shadcn@latest add @redpanda/collapsible
```

<ComponentPreview name="collapsible-demo" description="Uncontrolled collapsible — trigger toggles the panel locally." />

### Controlled

<ComponentPreview
  name="collapsible-controlled-demo"
  description="Drive `open` from parent state via `onOpenChange` and render different trigger icons per state."
/>

### Multiple independent collapsibles

<ComponentPreview
  name="collapsible-multiple-demo"
  description="Multiple independent collapsibles stacked vertically, each opens independently."
/>

### Disabled

<ComponentPreview name="collapsible-disabled-demo" description="Collapsible rendered in a disabled state." />

### Default open

<ComponentPreview
  name="collapsible-default-open-demo"
  description="Collapsible that starts expanded via the defaultOpen prop."
/>

### Chevron on leading edge

<ComponentPreview
  name="collapsible-chevron-start-demo"
  description="Collapsible with the chevron rendered on the leading edge rather than trailing."
/>

### Reveal sensitive content

<ComponentPreview
  name="collapsible-recovery-keys-demo"
  description="Reveal recovery keys pattern using a collapsible to hide sensitive content by default."
/>

## Usage

```tsx
<Collapsible>
  <CollapsibleTrigger>Collapsible Trigger</CollapsibleTrigger>
  <CollapsibleContent>Collapsible Content</CollapsibleContent>
</Collapsible>
```

## When to use

Use this decision tree to determine when to use the Collapsible component:

```mermaid
graph TD;
    A[❓ Need to hide/show content?] --> B{What type of interaction?};
    B --> C[✅ Click to expand/collapse];
    B --> D[⚠️ Hover to show content];
    B --> E[⚠️ Modal/overlay interaction];

    C --> F[❓ What content type?];
    D --> G[⚠️ Use HoverCard instead];
    E --> H[⚠️ Use Dialog/Popover instead];

    F --> I[✅ FAQ sections];
    F --> J[✅ Expandable lists];
    F --> K[✅ Settings panels];
    F --> L[⚠️ Navigation menus];

    I --> Q[❓ SEO important?];
    J --> Q;
    K --> Q;
    L --> N[⚠️ Use DropdownMenu instead];

    Q --> R[⚠️ Pass keepMounted to CollapsibleContent];
    Q --> S[ℹ️ Standard implementation];

    classDef recommended fill:#4ade80,stroke:#22c55e,stroke-width:2px,color:#000;
    classDef discouraged fill:#fbbf24,stroke:#f59e0b,stroke-width:2px,color:#000;
    classDef decision fill:#60a5fa,stroke:#3b82f6,stroke-width:2px,color:#fff;
    classDef neutral fill:#9ca3af,stroke:#6b7280,stroke-width:2px,color:#fff;

    class C,I,J,K recommended;
    class D,E,G,H,L,N,R discouraged;
    class A,B,F,Q decision;
    class S neutral;
```

## Props

<div className="flex flex-row gap-x-3">
  <ExternalLink href="https://base-ui.com/react/components/collapsible" text="Docs" />
  <ExternalLink href="https://base-ui.com/react/components/collapsible#api-reference" text="API Reference" />
</div>

## Keyboard interactions

| Key                                       | Action                                                                          |
| ----------------------------------------- | ------------------------------------------------------------------------------- |
| `Enter` / `Space` on `CollapsibleTrigger` | Toggles the panel open / closed.                                                |
| `Tab`                                     | Moves focus to the next focusable element (including into the panel when open). |

## Accessibility

- The trigger exposes `aria-expanded` + `aria-controls` pointing at the panel; Base UI sets the native `data-open`
  (root/trigger) / `data-panel-open` (panel) attributes you can target with CSS selectors.
- The trigger must be a real button (or another focusable element via the `render` prop); static `<div>` triggers lose
  keyboard activation.
- Use `keepMounted` on `CollapsibleContent` when the hidden content must remain in the DOM for SEO, intersection
  observers, or mid-animation measurements.

## Controlled vs uncontrolled

Uncontrolled — trigger toggles the panel locally:

```tsx lineNumbers
<Collapsible>
  <CollapsibleTrigger>Toggle</CollapsibleTrigger>
  <CollapsibleContent>{/* ... */}</CollapsibleContent>
</Collapsible>
```

Controlled — drive `open` from parent state (e.g. expand all / collapse all from a toolbar):

```tsx lineNumbers
const [open, setOpen] = useState(false);

<Collapsible open={open} onOpenChange={setOpen}>
  <CollapsibleTrigger>Toggle</CollapsibleTrigger>
  <CollapsibleContent>{/* ... */}</CollapsibleContent>
</Collapsible>;
```

## Don't delete from the DOM

The choice made (also Base UI's default) is to remove the element from the DOM for accessibility and performance reasons. However, this may pose a problem for SEO. If you want your Collapsible content to be taken into account by Google, **pass `keepMounted` to `CollapsibleContent`** — the closed panel stays in the DOM (hidden via the `hidden` attribute):

```tsx lineNumbers
<Collapsible>
  <CollapsibleTrigger>Toggle</CollapsibleTrigger>
  <CollapsibleContent keepMounted>{/* stays in the DOM while closed */}</CollapsibleContent>
</Collapsible>
```

To additionally let the browser's find-in-page (`Ctrl`/`Cmd` + `F`) reveal the closed content, use `hiddenUntilFound` instead (implies `keepMounted` and hides the panel with `hidden="until-found"`):

```tsx lineNumbers
<CollapsibleContent hiddenUntilFound>{/* discoverable by find-in-page */}</CollapsibleContent>
```

## Credits

- We use [Base UI](https://base-ui.com/react/components/collapsible) for the collapsible component.
- We take our inspiration from [Shadcn UI](https://ui.shadcn.com/docs/components/collapsible) for the collapsible style.
