# Accordion

> A stack of collapsible disclosure panels; expand one to read it, collapse it to reclaim space.

URL: https://apogee.avaui.dev/docs/accordion
Last updated: 2026-10-16

A stack of collapsible disclosure panels; expand one to read it, collapse it to reclaim space.

Last updated October 16, 2026

```astro
<Accordion>
<AccordionItem title="What is Apogee?">
  A copy-in Astro component library, styled with Tailwind and design tokens.
</AccordionItem>
<AccordionItem title="Does it ship JavaScript?">
  Only when a component genuinely needs it. Accordion is zero-JS — it's a native `<details>`.
</AccordionItem>
</Accordion>
```

## Add

```sh
npx @ava-ui/apogee add accordion
```

`AccordionItem` uses `@lucide/astro` (`ChevronDown`, `CirclePlus`, `CircleMinus`) for the disclosure icon.

## Usage

```astro
---
import Accordion from '@/components/apogee/Accordion/Accordion.astro'
import AccordionItem from '@/components/apogee/Accordion/AccordionItem.astro'
---
<Accordion>
  <AccordionItem title="Section one">Panel content.</AccordionItem>
  <AccordionItem title="Section two">Panel content.</AccordionItem>
</Accordion>
```

## Anatomy

-   **`Accordion`** — the bordered, divided container. Default slot holds one or more `AccordionItem`s.
-   **`AccordionItem`** — a native `<details>`. Its `title` prop renders the `<summary>` row (label + chevron); its default slot is the panel body.

## API

`@composable` — both exposed to Content Editors in AVA. Any other native attribute (e.g. `id`, `data-*`) passes through on either component.

**`Accordion`**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'outline' \| 'plain'` | `'outline'` | A bordered box, or dividers only. |
| `class` | `string` | — | Extra classes, merged last. |

**`AccordionItem`**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | — | The `<summary>` label; the `trigger` slot replaces it with rich content. |
| `iconPosition` | `'start' \| 'end'` | `'end'` | Icon side. |
| `icon` | `'chevron' \| 'plus'` | `'chevron'` | A chevron that flips, or a circled plus that turns to a minus. |
| `variant` | `'plain' \| 'card'` | `'plain'` | `card` sets the item on a rounded card, tinted while open. Stack cards in a `flex flex-col gap-2` wrapper instead of `Accordion`. |
| `size` | `'medium' \| 'large'` | `'medium'` | `large` for FAQ-sized questions and answers. |
| `group` | `string` | — | Shared across items → single-open (exclusive): opening one closes the rest with the same `group`. Maps to `<details name>`. |
| `open` | `boolean` | `false` | Open on load. |
| `class` | `string` | — | Extra classes, merged last. |

## Trigger slot and icon position

The `trigger` slot replaces `title` with rich content; `iconPosition` moves the chevron.

```astro
<Accordion>
<AccordionItem iconPosition="start" title="Chevron first">…</AccordionItem>
<AccordionItem>
  <span slot="trigger" class="flex items-center gap-2">Billing <Badge color="positive">Paid</Badge></span>
  …
</AccordionItem>
</Accordion>
```

## Variants

A plain list with plus icons at the large size, and a stack of cards:

```astro
<Accordion variant="plain">
<AccordionItem title="Is there a free trial?" icon="plus" size="large" group="plain" open>Yes, 30 days.</AccordionItem>
<AccordionItem title="Can I change plans later?" icon="plus" size="large" group="plain">Any time.</AccordionItem>
</Accordion>
<div class="flex flex-col gap-2">
<AccordionItem title="Is there a free trial?" icon="plus" variant="card" iconPosition="start" group="cards" open>Yes, 30 days.</AccordionItem>
<AccordionItem title="Can I change plans later?" icon="plus" variant="card" iconPosition="start" group="cards">Any time.</AccordionItem>
</div>
```

## States

Default closed, open on load (`open`), and exclusive group (shared `group` — opening one closes its siblings):

```astro
<Accordion>
<AccordionItem title="Closed by default">Collapsed until clicked.</AccordionItem>
<AccordionItem title="Open on load" open>Visible immediately.</AccordionItem>
</Accordion>
<Accordion>
<AccordionItem title="One" group="faq">Only one of these three stays open.</AccordionItem>
<AccordionItem title="Two" group="faq">Opening this closes "One" and "Three".</AccordionItem>
<AccordionItem title="Three" group="faq">Exclusive via the shared `group` name.</AccordionItem>
</Accordion>
```

## Examples

A single-panel FAQ, exclusive within itself, pre-opening the first item:

```astro
<Accordion>
  <AccordionItem title="Shipping times" group="faq" open>
    3–5 business days domestic.
  </AccordionItem>
  <AccordionItem title="Return policy" group="faq">
    30 days, unworn, with tags.
  </AccordionItem>
</Accordion>
```

## Accessibility

| Key | Action |
| --- | --- |
| `Tab` | Moves focus to the next item header. |
| `Shift` `Tab` | Moves focus to the previous item header. |
| `Enter` `Space` | Opens or closes the focused item. |

-   The chevron or plus icon is `aria-hidden`; the visible label is the accessible name.
-   Exclusive grouping uses the native `<details name>` attribute — no JS, no ARIA wiring needed.
-   Height animation respects `prefers-reduced-motion` (transitions are removed).

## Tokens

| Token | Used for |
| --- | --- |
| `--border-neutral` | Container border + divider between items |
| `--foreground-neutral` | Summary label text |
| `--foreground-neutral-faded` | Chevron icon + panel body text |
| `--outline-color-focus` | Focus ring on the summary |
| `--duration-medium` / `ease-standard` | Chevron rotation |
| `--duration-slow` / `ease-standard` | Panel height/reveal transition |

## Do / Don’t

-   **Do** use a shared `group` for FAQ-style lists where only one answer should show at a time.
-   **Do** pre-open the most relevant item with `open` rather than making users hunt.
-   **Don’t** nest interactive controls (another accordion, a form) inside a panel without checking focus order.
-   **Don’t** rely on JS for toggling — there isn’t any; it’s native disclosure.

## Content

-   Titles are short questions or labels, sentence case, no ending period.
-   Panel body writes complete sentences — it’s read as prose once opened, not a label.

## Related

[

CollapsibleA single show/hide region, built on native <details>. Zero JS.

](https://apogee.avaui.dev/docs/collapsible)[

ExpandableLong content clamped to a preview height with a fade and a "Show more" toggle. Zero JS.

](https://apogee.avaui.dev/docs/expandable)[

ContentToggleShows one keyed child at a time and slides between them, for pagers and step content.

](https://apogee.avaui.dev/docs/content-toggle)
