# Collapsible

A region of content that the user can show and hide with a trigger.

```tsx
import { ChevronsUpDownIcon } from "lucide-react"
import { Button } from "@zenoxai/ui/components/button"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@zenoxai/ui/components/collapsible"

function CollapsibleDemo() {
  return (
    <Collapsible className="flex w-full max-w-sm flex-col gap-2">
      <div className="flex items-center justify-between gap-4">
        <span className="text-sm font-medium text-text-primary">
          3 related alerts
        </span>
        <CollapsibleTrigger
          render={
            <Button
              variant="ghost"
              size="icon-sm"
              aria-label="Toggle related alerts"
            />
          }
        >
          <ChevronsUpDownIcon />
        </CollapsibleTrigger>
      </div>
      <div className="rounded-md border border-border px-3 py-2 font-mono text-sm">
        acme-login.co
      </div>
      <CollapsibleContent className="flex flex-col gap-2">
        <div className="rounded-md border border-border px-3 py-2 font-mono text-sm">
          acme-support.net
        </div>
        <div className="rounded-md border border-border px-3 py-2 font-mono text-sm">
          acrne.com
        </div>
      </CollapsibleContent>
    </Collapsible>
  )
}
```

## Usage

```tsx
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@zenoxai/ui/components/collapsible"
```

```tsx
<Collapsible>
  <CollapsibleTrigger>Show related alerts</CollapsibleTrigger>
  <CollapsibleContent>...</CollapsibleContent>
</Collapsible>
```

Use a collapsible for one optional region: related records, advanced filters, the raw payload
of an event. The trigger carries no styles, so it looks like whatever you render; style it as
a [Button](/components/button) through `render`. The content has no look of its own either,
but its height animates open and closed with the same motion as an
[Accordion](/components/accordion) panel. It clips its children while it moves, so leave room
for focus rings of controls placed at its edges.

For several sections in a row, use an Accordion, which also handles
keyboard movement between the headings.

## Examples

### Controlled

Pass `open` and `onOpenChange` when other parts of the page need the state, for example to
change the trigger label.

```tsx
import * as React from "react"
import { Button } from "@zenoxai/ui/components/button"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@zenoxai/ui/components/collapsible"

function CollapsibleControlled() {
  const [open, setOpen] = React.useState(false)

  return (
    <Collapsible
      open={open}
      onOpenChange={setOpen}
      className="flex w-full max-w-sm flex-col gap-3"
    >
      <CollapsibleTrigger
        render={<Button variant="outline" className="w-fit" />}
      >
        {open ? "Hide advanced filters" : "Show advanced filters"}
      </CollapsibleTrigger>
      <CollapsibleContent>
        <ul className="flex flex-col gap-1 rounded-md bg-surface-muted p-3 text-sm text-text-secondary">
          <li>Detection source: Domain monitoring</li>
          <li>First seen: last 30 days</li>
          <li>Tenant: Acme Corp</li>
        </ul>
      </CollapsibleContent>
    </Collapsible>
  )
}
```

## Accessibility

- The trigger is a button with `aria-expanded` and `aria-controls` pointing to the content.
  Enter and Space toggle it.
- An icon-only trigger needs an `aria-label` that names the content it shows ("Toggle related
  alerts").
- The content is unmounted while closed. Set `keepMounted` on `CollapsibleContent` to keep it
  in the DOM, or `hiddenUntilFound` so find-in-page can open it.

## API reference

`import { ... } from "@zenoxai/ui/components/collapsible"`

### Collapsible

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| defaultOpen | `boolean` | `false` | Whether the collapsible panel is initially open.  To render a controlled collapsible, use the `open` prop instead. |
| disabled | `boolean` | `false` | Whether the component should ignore user interaction. |
| onOpenChange | `((open: boolean, eventDetails: CollapsibleRootChangeEventDetails) => void)` |  | Event handler called when the panel is opened or closed. |
| open | `boolean` |  | Whether the collapsible panel is currently open.  To render an uncontrolled collapsible, use the `defaultOpen` prop instead. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, CollapsibleRootState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### CollapsibleTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| nativeButton | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`). |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, CollapsibleTriggerState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### CollapsibleContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| hiddenUntilFound | `boolean` | `false` | Allows the browser's built-in page search to find and expand the panel contents.  Overrides the `keepMounted` prop and uses `hidden="until-found"` to hide the element without removing it from the DOM. |
| keepMounted | `boolean` | `false` | Whether to keep the element in the DOM while the panel is hidden. This prop is ignored when `hiddenUntilFound` is used. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, CollapsiblePanelState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

