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

Last updated

What is Apogee?

A copy-in Astro component library, styled with Tailwind and design tokens.

Does it ship JavaScript?

Only when a component genuinely needs it. Accordion is zero-JS — it’s a native <details>.

Show code
<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

npx @ava-ui/apogee add accordion

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

Usage

---
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 AccordionItems.
  • 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.

Chevron first
The chevron sits before the title.
Chevron last (default)
The chevron sits after the title.
Billing Paid

A rich summary with a badge.

Show code
<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:

Is there a free trial?
Yes, you can try it free for 30 days.
Can I change plans later?
Any time, from your billing settings.
Is there a free trial?
Yes, you can try it free for 30 days.
Can I change plans later?
Any time, from your billing settings.
Show code
<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):

Closed by default
Collapsed until clicked.
Open on load
Visible immediately.
One
Only one of these three stays open.
Two
Opening this closes “One” and “Three”.
Three
Exclusive via the shared group name.
Show code
<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:

<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.