# I9kCollapsible

> Native, independently expanding disclosure surface with slots for rich summary and body content.

```ts
import { I9kCollapsible } from '@9klabs/design';
```

## Examples

### Closed

```vue
<I9kCollapsible>
  <template #summary>Course module</template>
  <p>Module lessons and resources.</p>
</I9kCollapsible>
```

### Initially open

```vue
<I9kCollapsible :default-open="true">
  <template #summary>Course module</template>
  <p>This body is visible when the example first renders.</p>
</I9kCollapsible>
```

### Rich summary

```vue
<I9kCollapsible>
  <template #summary><span><strong>Module 03</strong> · 9 topics</span></template>
  <ol><li>Plan</li><li>Design</li><li>Build</li></ol>
</I9kCollapsible>
```

### Flush, in a list

```vue
<div style="display: grid; gap: var(--spacing-2); max-width: 20rem">
  <I9kCollapsible variant="flush" :default-open="true">
    <template #summary>01 · Getting started</template>
    <ol><li>Welcome</li><li>Setup</li></ol>
  </I9kCollapsible>
  <I9kCollapsible variant="flush">
    <template #summary>02 · Prompting</template>
    <ol><li>Context</li></ol>
  </I9kCollapsible>
</div>
```

### Independent instances

```vue
<div style="display: grid; gap: var(--spacing-6)">
  <I9kCollapsible :default-open="true"><template #summary>First</template><p>Open together.</p></I9kCollapsible>
  <I9kCollapsible :default-open="true"><template #summary>Second</template><p>Also open.</p></I9kCollapsible>
</div>
```

### Controlled

```vue
<button type="button" @click="open = !open">{{ open ? 'Collapse' : 'Expand' }}</button>
<I9kCollapsible v-model:open="open">
  <template #summary>Course module</template>
  <p>The parent owns whether this body is visible.</p>
</I9kCollapsible>
```

### Arabic RTL

```vue
<div dir="rtl" lang="ar">
  <I9kCollapsible :default-open="true">
    <template #summary>الوحدة الأولى</template>
    <p>محتوى الوحدة وتفاصيلها.</p>
  </I9kCollapsible>
</div>
```

## Watch out

- `defaultOpen` controls only the initial state; bind `v-model:open` for a controlled disclosure such as expand-all.
- A one-way `:open` binding does not learn about user toggles; use `v-model:open` so the parent value stays in step.
- Uncontrolled sibling instances expand independently; control them with `v-model:open` if only one section may be open.
- Provide visible summary content because the summary slot is the disclosure control label.
- Use `variant="flush"` for disclosures listed inside a panel or sidebar; the default card is meant to stand on the page.

## API

### Props

| Prop | Type | Default | Required |
| --- | --- | --- | --- |
| `defaultOpen` | `boolean` | `false` | no |
| `open` | `boolean` | `undefined` | no |
| `variant` | `'card' \| 'flush'` | `'card'` | no |

### Emits

| Event | Payload |
| --- | --- |
| `toggle` | `[open: boolean]` |
| `update:open` | `[open: boolean]` |

### Slots

- `summary`
- `default`

## Agent prompt

```text
Use I9kCollapsible from @9klabs/design for a single branded disclosure that may contain rich Vue markup.

import { I9kCollapsible } from '@9klabs/design';

Props:
- defaultOpen?: boolean (default false) — sets only the initial native open state when `open` is not bound.
- open?: boolean (default undefined) — bind with v-model:open to control the open state from the parent, e.g. an expand-all / collapse-all button. Leave it unbound for the browser-managed, uncontrolled behavior.
- variant?: 'card' | 'flush' (default 'card') — `flush` drops the border and background, for a list of disclosures inside a panel or a sidebar.

Emits:
- toggle(open: boolean) — reports the current native details.open value after every native toggle, including one caused by changing a bound `open`.
- update:open(open: boolean) — emitted only when `open` is bound and a user toggle makes the native state differ from it.

Slots:
- summary — content rendered inside the native <summary>.
- default — content rendered in the disclosure body.

Behavior: the component renders native <details>/<summary>. Unless `open` is bound, each instance owns its browser-managed state, so siblings expand independently and any number may stay open. When `open` is bound, changing it opens or closes the disclosure, and a user toggle is reported through update:open.

IMPORTANT: `defaultOpen` is only an initial-state option; bind `open` (v-model:open) when the parent must set the state, such as expand-all. A bound `open` without a listener for update:open does not follow user toggles back into the parent — use v-model:open, not a one-way :open.

Usage:
<I9kCollapsible :default-open="true" @toggle="(open) => console.log(open)">
  <template #summary><strong>Module 01</strong> · 7 topics</template>
  <ol><li>What is coding?</li><li>Engineering judgment</li></ol>
</I9kCollapsible>
```
