# Collapsible

A region that one trigger shows and hides.

```tsx
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger, Field, Input } from 'ferry-ui'
import { ChevronRight } from 'lucide-react'

export default function CollapsibleHero() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-4">
      <Field label="Project name">
        <Input defaultValue="Website redesign" />
      </Field>
      <Collapsible className="flex flex-col gap-4">
        <CollapsibleTrigger asChild>
          <Button
            variant="ghost"
            className="group w-fit"
            icon={<ChevronRight className="transition-transform group-data-[state=open]:rotate-90" />}
          >
            Advanced options
          </Button>
        </CollapsibleTrigger>
        <CollapsibleContent className="flex flex-col gap-4">
          <Field label="URL slug">
            <Input mono defaultValue="website-redesign" />
          </Field>
          <Field label="Task prefix">
            <Input mono defaultValue="WEB" />
          </Field>
        </CollapsibleContent>
      </Collapsible>
    </div>
  )
}
```

## Usage guidelines

- **Content that can wait.** Use a collapsible for advanced options or for the rest of a long list.
- **No look of its own.** A collapsible has no style. Style the trigger and the content with your classes.
- **Not for panels.** To show one panel of a set, use [Tabs](/docs/components/tabs).
- **Not for content above the page.** For an overlay, use [Popover](/docs/components/popover) or [Dropdown Menu](/docs/components/dropdown-menu).

## Anatomy

Import the parts and put them together.

```tsx title="Anatomy"

<Collapsible>
  <CollapsibleTrigger />
  <CollapsibleContent />
</Collapsible>
```

| Part | Role |
| --- | --- |
| `Collapsible` | Holds the open state. |
| `CollapsibleTrigger` | The button that opens and closes the region. It sets `aria-expanded`. |
| `CollapsibleContent` | The region. It unmounts when the collapsible is closed. |

## Examples

### Trigger

Use `asChild` to make a [Button](/docs/components/button) the trigger. The trigger and the content have a `data-state` attribute with the value `open` or `closed`. Use it in your classes, for example to turn a chevron.

```tsx
<CollapsibleTrigger asChild>
  <Button
    variant="ghost"
    className="group"
    icon={<ChevronRight className="transition-transform group-data-[state=open]:rotate-90" />}
  >
    Advanced options
  </Button>
</CollapsibleTrigger>
```

### Open state

A collapsible holds its open state by default. Use `defaultOpen` to open it at the start.

To control the state, pass `open` and `onOpenChange`. Use this when other content follows the state, for example the label of the trigger.

```tsx
import * as React from 'react'
import { Button, Card, Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ferry-ui'

const MEMBERS = ['Maya Chen', 'Liam Novak', 'Sara Ortiz', 'Tom Becker', 'Aiko Tanaka', 'Omar Haddad']

export default function CollapsibleControlled() {
  const [open, setOpen] = React.useState(false)
  const first = MEMBERS.slice(0, 3)
  const rest = MEMBERS.slice(3)

  return (
    <Card className="w-full max-w-sm">
      <Collapsible open={open} onOpenChange={setOpen}>
        <ul className="divide-y text-[13px] text-foreground">
          {first.map((member) => (
            <li key={member} className="px-4 py-2.5">
              {member}
            </li>
          ))}
        </ul>
        <CollapsibleContent asChild>
          <ul className="divide-y border-t text-[13px] text-foreground">
            {rest.map((member) => (
              <li key={member} className="px-4 py-2.5">
                {member}
              </li>
            ))}
          </ul>
        </CollapsibleContent>
        <div className="border-t p-1.5">
          <CollapsibleTrigger asChild>
            <Button variant="ghost" size="tiny" className="w-full">
              {open ? 'Show less' : `Show ${rest.length} more`}
            </Button>
          </CollapsibleTrigger>
        </div>
      </Collapsible>
    </Card>
  )
}
```

### Animation

The content has no animation by default. Add these classes to `CollapsibleContent` to slide it:

```text
overflow-hidden data-[state=open]:animate-collapsible-down data-[state=closed]:animate-collapsible-up
```

Put the padding on an element in the content. The animation changes the height of the content.

```tsx
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ferry-ui'
import { ChevronRight } from 'lucide-react'

export default function CollapsibleAnimated() {
  return (
    <Collapsible className="flex w-full max-w-sm flex-col">
      <CollapsibleTrigger asChild>
        <Button
          variant="ghost"
          className="group w-fit"
          icon={<ChevronRight className="transition-transform group-data-[state=open]:rotate-90" />}
        >
          Payment terms
        </Button>
      </CollapsibleTrigger>
      <CollapsibleContent className="overflow-hidden data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down">
        {/* The padding is on an inner element: the animation changes the height of the content. */}
        <p className="px-2.5 pt-2 text-[13px] text-foreground-light">
          The customer pays each invoice in 30 days. A late payment adds a fee of 2% to the next invoice.
        </p>
      </CollapsibleContent>
    </Collapsible>
  )
}
```

### Disabled state

Set `disabled` on `Collapsible` to keep its state. The trigger refuses clicks.

```tsx
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ferry-ui'
import { ChevronRight } from 'lucide-react'

export default function CollapsibleDisabled() {
  return (
    <Collapsible disabled className="flex flex-col gap-2">
      <CollapsibleTrigger asChild>
        <Button variant="ghost" icon={<ChevronRight />}>
          Advanced options
        </Button>
      </CollapsibleTrigger>
      <CollapsibleContent className="text-[13px] text-foreground-light">
        The options of the project.
      </CollapsibleContent>
    </Collapsible>
  )
}
```

## API reference

Each part also accepts the props of its Radix UI primitive and the attributes of its element.

### Collapsible

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultOpen` | `boolean` |  |  |
| `open` | `boolean` |  |  |
| `disabled` | `boolean` |  |  |
| `onOpenChange` | `((open: boolean) => void)` |  |  |
| `asChild` | `boolean` |  |  |

### CollapsibleTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` |  |  |

### CollapsibleContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `forceMount` | `true` |  | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. |
| `asChild` | `boolean` |  |  |
