# Accordion

> Collapsible panels with single or multiple expansion modes and full keyboard support.

- Package: `@sisyphos-ui/accordion`
- Docs: https://sisyphosui.com/docs/components/accordion
- npm: https://www.npmjs.com/package/@sisyphos-ui/accordion

## Installation

```bash
pnpm add @sisyphos-ui/accordion @sisyphos-ui/core
```

Or use the umbrella package:

```bash
pnpm add @sisyphos-ui/ui
```

## Import

```tsx
import "@sisyphos-ui/accordion/styles.css";
import { Accordion } from "@sisyphos-ui/accordion";
```

## Examples

### Default

`Accordion.Item`, `Trigger`, and `Content` compose a disclosure list.

```tsx
import { Accordion } from "@sisyphos-ui/ui";

export function Example() {
  return (
    <Accordion defaultValue="item-1" className="w-full max-w-md">
      <Accordion.Item value="item-1">
        <Accordion.Trigger>How is Sisyphos UI themed?</Accordion.Trigger>
        <Accordion.Content>
          Every token is a CSS variable under <code>--sisyphos-*</code>. Override them globally
          or scoped to any DOM subtree.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="item-2">
        <Accordion.Trigger>What React versions are supported?</Accordion.Trigger>
        <Accordion.Content>
          React 17, 18, and 19. All components are <code>forwardRef</code> with stable <code>displayName</code>.
        </Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="item-3">
        <Accordion.Trigger>Is tree-shaking supported?</Accordion.Trigger>
        <Accordion.Content>
          Yes. Install the umbrella for DX, or import individual component packages for the smallest footprint.
        </Accordion.Content>
      </Accordion.Item>
    </Accordion>
  );
}
```

### Multiple expansion

`multiple` lets several panels open at once. Pass a `string[]` to `defaultValue` / `value`.

```tsx
import { Accordion } from "@sisyphos-ui/ui";

export function Example() {
  return (
    <Accordion multiple defaultValue={["shipping", "returns"]}>
      <Accordion.Item value="shipping">
        <Accordion.Trigger>Shipping & delivery</Accordion.Trigger>
        <Accordion.Content>Orders placed before 4pm ship same day.</Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="returns">
        <Accordion.Trigger>Returns</Accordion.Trigger>
        <Accordion.Content>30-day window, no questions asked.</Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="warranty">
        <Accordion.Trigger>Warranty</Accordion.Trigger>
        <Accordion.Content>Two years on all hardware defects.</Accordion.Content>
      </Accordion.Item>
    </Accordion>
  );
}
```

### Ghost variant

Borderless chrome for accordions nested inside other containers.

```tsx
import { Accordion } from "@sisyphos-ui/ui";

export function Example() {
  return (
    <Accordion variant="ghost" defaultValue="a">
      <Accordion.Item value="a">
        <Accordion.Trigger>Minimal, borderless chrome</Accordion.Trigger>
        <Accordion.Content>Use when the accordion sits inside another container.</Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="b">
        <Accordion.Trigger>Quiet density</Accordion.Trigger>
        <Accordion.Content>Less visual weight, same keyboard & ARIA behavior.</Accordion.Content>
      </Accordion.Item>
    </Accordion>
  );
}
```

### Disabled item

Mark individual items `disabled`. The trigger stays focusable for screen readers.

```tsx
import { Accordion } from "@sisyphos-ui/ui";

export function Example() {
  return (
    <Accordion defaultValue="plan-free">
      <Accordion.Item value="plan-free">
        <Accordion.Trigger>Free plan</Accordion.Trigger>
        <Accordion.Content>Always available. Up to 3 projects.</Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="plan-pro">
        <Accordion.Trigger>Pro plan</Accordion.Trigger>
        <Accordion.Content>Unlimited projects, priority support.</Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="plan-enterprise" disabled>
        <Accordion.Trigger>Enterprise · contact sales</Accordion.Trigger>
        <Accordion.Content>Disabled — trigger is focusable but not toggleable.</Accordion.Content>
      </Accordion.Item>
    </Accordion>
  );
}
```

### Controlled

Sync with external state via `value` + `onValueChange`. Pass `null` to collapse all.

```tsx
import { useState } from "react";
import { Accordion } from "@sisyphos-ui/ui";

export function Example() {
  const [value, setValue] = useState<string | null>("overview");

  return (
    <>
      <p>Active: {value ?? "none"} <button onClick={() => setValue(null)}>collapse all</button></p>
      <Accordion value={value} onValueChange={setValue}>
        <Accordion.Item value="overview">
          <Accordion.Trigger>Overview</Accordion.Trigger>
          <Accordion.Content>Sync the open panel with external state.</Accordion.Content>
        </Accordion.Item>
        <Accordion.Item value="details">
          <Accordion.Trigger>Details</Accordion.Trigger>
          <Accordion.Content>Pass `value` + `onValueChange`. Use `null` to collapse all.</Accordion.Content>
        </Accordion.Item>
      </Accordion>
    </>
  );
}
```
