# Accordion

Displays a vertically stacked set of interactive headings that reveal one or more content panels.

Use Accordion for FAQ blocks, settings groups, and progressive disclosure where content should stay in the same page flow.

## Import

```ts
import {
  AccordionComponent,
  AccordionContentComponent,
  AccordionItemComponent,
  AccordionTriggerComponent,
} from '@edsis/component/accordion';
```

## Composition

The Angular structure mirrors the shadcn and Radix composition while using Angular selectors and a native button trigger.

```text
Accordion
├── AccordionItem
│   ├── button[AccordionTrigger]
│   └── AccordionContent
└── AccordionItem
    ├── button[AccordionTrigger]
    └── AccordionContent
```

## Basic usage

Use `Accordion` as the root, wrap each section in `AccordionItem`, place the clickable heading on a native button with `AccordionTrigger`, and project body copy into `AccordionContent`.

Bind `[(value)]` when the parent should control the open state or seed a default open item.

```html
<Accordion [(value)]="openItem" type="single" class="w-full max-w-xl">
  <AccordionItem value="item-1">
    <button AccordionTrigger>Is it accessible?</button>
    <AccordionContent>
      Yes. The trigger and content follow the expected accordion ARIA wiring.
    </AccordionContent>
  </AccordionItem>
</Accordion>
```

## Common patterns

### Single-open FAQ

Use `type="single"` when only one item should stay open at a time.

```ts
const basicOpen = signal<string | string[] | null>('item-1');

<Accordion [(value)]="basicOpen" type="single" class="max-w-lg">
  <AccordionItem value="item-1">...</AccordionItem>
  <AccordionItem value="item-2">...</AccordionItem>
  <AccordionItem value="item-3">...</AccordionItem>
</Accordion>
```

### Multiple open sections

Use `type="multiple"` when more than one panel should stay open. The bound value becomes a `string[]`.

```ts
const multipleOpen = signal<string[] | null>(['notifications']);

<Accordion [(value)]="multipleOpen" type="multiple" class="max-w-lg">
  <AccordionItem value="notifications">...</AccordionItem>
  <AccordionItem value="privacy">...</AccordionItem>
  <AccordionItem value="billing">...</AccordionItem>
</Accordion>
```

### Disabled items

Disable an individual item with `[disabled]="true"` on `AccordionItem`.

```ts
const disabledOpen = signal<string | string[] | null>('history');

<Accordion [(value)]="disabledOpen" type="single" class="w-full">
  <AccordionItem value="history">...</AccordionItem>
  <AccordionItem value="premium" [disabled]="true">...</AccordionItem>
  <AccordionItem value="email">...</AccordionItem>
</Accordion>
```

### Bordered list

Add borders on the root and the items when the accordion should read like a boxed settings list.

```ts
const borderOpen = signal<string | string[] | null>('billing');

<Accordion [(value)]="borderOpen" type="single" class="max-w-lg rounded-lg border">
  <AccordionItem value="billing" class="border-b px-4 last:border-b-0">...</AccordionItem>
  <AccordionItem value="security" class="border-b px-4 last:border-b-0">...</AccordionItem>
  <AccordionItem value="integrations" class="border-b px-4 last:border-b-0">...</AccordionItem>
</Accordion>
```

### Inside a card

Accordion works well inside `Card` when the disclosure belongs to a larger billing or account surface.

```ts
const cardOpen = signal<string | string[] | null>('plans');

<Card class="w-full max-w-sm">
  <CardHeader>
    <CardTitle>Subscription and billing</CardTitle>
    <CardDescription>Common questions about plans, payments, and cancellations.</CardDescription>
  </CardHeader>
  <CardContent>
    <Accordion [(value)]="cardOpen" type="single">
      <AccordionItem value="plans">...</AccordionItem>
      <AccordionItem value="billing">...</AccordionItem>
      <AccordionItem value="cancel">...</AccordionItem>
    </Accordion>
  </CardContent>
</Card>
```

### RTL

For right-to-left interfaces, set `dir="rtl"` on a wrapping container or manage direction globally in the app shell. The Accordion structure itself does not change.

```html
<section dir="rtl" lang="ar" class="max-w-md text-right">
  <Accordion [(value)]="rtlOpen" type="single">
    <AccordionItem value="item-1">...</AccordionItem>
    <AccordionItem value="item-2">...</AccordionItem>
    <AccordionItem value="item-3">...</AccordionItem>
  </Accordion>
</section>
```

## API reference

### `AccordionComponent`

| Input           | Type                         | Default    |
| --------------- | ---------------------------- | ---------- |
| `type`          | `'single' \| 'multiple'`     | `'single'` |
| `collapsible`   | `boolean`                    | `true`     |
| `value` (model) | `string \| string[] \| null` | `null`     |
| `class`         | `string`                     | `''`       |

### `AccordionItemComponent`

| Input      | Type      | Default |
| ---------- | --------- | ------- |
| `value`    | `string`  | —       |
| `disabled` | `boolean` | `false` |
| `class`    | `string`  | `''`    |

### Parts

- `button[AccordionTrigger]` renders the interactive heading and manages `aria-controls` plus `aria-expanded`.
- `AccordionContent` renders the panel region and links back to the trigger with `aria-labelledby`.
- Lower-level primitive behavior is based on the Radix Accordion pattern: <https://www.radix-ui.com/primitives/docs/components/accordion#api-reference>.

## Styling and theming

Pass `class` to the root or item parts to tune width, spacing, borders, and embedded-card layouts.

The component follows the shared library theme tokens, so standard utility classes such as `border`, `rounded-lg`, `bg-card`, `text-foreground`, and spacing utilities work as expected.

## Accessibility

- Trigger has `aria-expanded` and `aria-controls` pointing at the content id.
- Content has `role="region"` and `aria-labelledby` pointing back at the trigger id.
- `disabled` items remain visible but non-interactive and are marked with `aria-disabled`.
- Keep trigger text descriptive and avoid placing nested interactive controls inside the trigger button.

## Keyboard interactions

- Native button activation covers Enter and Space.
- Tab order follows the DOM order of the triggers and content.

## Angular notes

- The component uses Angular signal-based `model()` binding for `value`.
- For `type="single"`, the value is a `string | null`.
- For `type="multiple"`, the value is a `string[] | null`.
- Seed the initial open state with a signal rather than a separate `defaultValue` prop.

## Source parity

This Angular implementation follows the shadcn Accordion concepts while translating the examples to Angular selectors, standalone imports, and signal-friendly bindings.
