Layout · astro-ui · Accordion

Accordion

Collapsible sections built on native details/summary — zero JS.

Accordion provides collapsible content sections on native <details>/<summary>: expand/collapse, keyboard (Space/Enter), and announcements come from the platform. A bordered variant and chevron indicator round out the presentation.

Features

  • Native <details>/<summary> — keyboard and AT for free
  • single mode via the native name attribute (Chrome 120+)
  • 3 variants: default, bordered, ghost
  • Chevron indicator with rotation
  • Optional height animation via `animated` (pure CSS, graceful fallback)
  • SSR-controlled open panels via item.open

Usage

---
import { Accordion } from "astro-ui";
---

<Accordion
  id="faq"
  items={[
    { value: "q1", title: "What is astro-ui?", content: "A zero-JS Astro component library." },
    { value: "q2", title: "Does it need JavaScript?", content: "Not for the accordion — it's native details." },
  ]}
/>

Demos

Basic

What is astro-ui?
A zero-JS Astro component library.
Does it need JavaScript?
Not for this accordion — it's native details.
<Accordion
  items={[
    { value: "q1", title: "What is astro-ui?", content: "A zero-JS Astro component library." },
    { value: "q2", title: "Does it need JS?", content: "Not for this." },
  ]}
/>

Bordered & pre-opened

Opened
This panel starts open.
Closed
Click to expand.
<Accordion variant="bordered"
  items={[
    { value: "a", title: "Opened", content: "This panel starts open.", open: true },
    { value: "b", title: "Closed", content: "Click to expand." },
  ]}
/>

Animated expand

Smooth height
The panel animates open and closed instead of snapping.
Still zero JS
Pure CSS: ::details-content + interpolate-size. Unsupported browsers snap instantly.
<Accordion animated
  items={[
    { value: "a", title: "Smooth height", content: "The panel animates open and closed instead of snapping." },
    { value: "b", title: "Still zero JS", content: "Pure CSS: ::details-content + interpolate-size. Unsupported browsers snap instantly." },
  ]}
/>

API

Props

PropTypeDefaultDescription
itemsAccordionItem[][]Sections: { value, title, content, open?, disabled? }.
singlebooleanfalseOne-open-at-a-time via native name attribute.
animatedbooleanfalseSmooth expand/collapse height animation (CSS-only).
variant"default" | "bordered" | "ghost""default"Visual style.
size"sm" | "md" | "lg""md"Text/padding scale.
indicatorbooleantrueRotating chevron.
ariaLabelstring—Accessible name for the group.
classstring—Merged via cn(); Tailwind classes welcome.
idstring—Element id.

Accessibility

Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.

  • Native <details>/<summary> — expand/collapse state, Space/Enter activation, and screen-reader announcements come from the platform
  • Disabled summaries are skipped by keyboard and assistive tech
  • Focus-visible ring on summaries via :focus-visible

FAQ

How does single mode work without JS?

Native <details name="group"> exclusivity (Chrome 120+). Elsewhere panels toggle independently — behavior degrades gracefully.

Can content be arbitrary markup?

Use the item.content string for text, or compose the component differently — the items API keeps SSR output fully static.

How does the animation work?

`animated` animates the native ::details-content pseudo between block-size 0 and auto (interpolate-size: allow-keywords). Browsers without support ignore it and snap instantly — never broken.

Changelog

Version history mentioning Accordion.

v0.1.0 — 2026-11-11
added
  • Layout (7): Card, AspectRatio, ScrollArea, Separator, Accordion, Collapsible, StickySurface.
  • Native-first interactive behavior: Dialog, AlertDialog, and Sheet on <dialog>; Accordion and Collapsible on <details>; Tabs, Menu, Tree, and Combobox with WAI-ARIA roles and scoped keyboard scripts.