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?
Does it need JavaScript?
<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
Closed
<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
Still zero JS
<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
| Prop | Type | Default | Description |
|---|---|---|---|
items | AccordionItem[] | [] | Sections: { value, title, content, open?, disabled? }. |
single | boolean | false | One-open-at-a-time via native name attribute. |
animated | boolean | false | Smooth expand/collapse height animation (CSS-only). |
variant | "default" | "bordered" | "ghost" | "default" | Visual style. |
size | "sm" | "md" | "lg" | "md" | Text/padding scale. |
indicator | boolean | true | Rotating chevron. |
ariaLabel | string | — | Accessible name for the group. |
class | string | — | Merged via cn(); Tailwind classes welcome. |
id | string | — | 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.
- 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.