Askr
UI & Components

Accordion and Collapsible

Use accordion and collapsible with the current published Askr packages.

  • @askrjs/ui/accordion0.0.13
  • @askrjs/ui/collapsible0.0.13
  • @askrjs/themes/accordion0.0.13
  • @askrjs/themes/collapsible0.0.13

How to use accordion and collapsible

Accordion and Collapsible should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.

  1. Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
  2. Keep accordion and collapsible labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
  3. Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@askrjs/themes/components';

<Accordion type="single" collapsible>
  <AccordionItem value="billing">
    <AccordionTrigger>How billing works</AccordionTrigger>
    <AccordionContent>Usage is calculated per workspace.</AccordionContent>
  </AccordionItem>
</Accordion>

Purpose

Accordion groups several related disclosures — think an FAQ list or a settings panel — and manages roving keyboard focus and open state across all of them at once. Collapsible is the single-region primitive Accordion is effectively built from: reach for it when you have one thing to show or hide, and reach for Accordion once you have a list of items sharing that same behavior.

Install and import

Install `@askrjs/ui` for the headless behavior and `@askrjs/themes` for the styled defaults. Pull Accordion pieces from `@askrjs/ui/accordion` (headless) or `@askrjs/themes/accordion` (styled), and Collapsible pieces from `@askrjs/ui/collapsible` or `@askrjs/themes/collapsible` — the two components ship as separate subpaths in both packages, not one combined module.

Live examples

The examples on this page render the themed Accordion and Collapsible directly, so you can toggle items, inspect the resulting `data-state` and `aria-expanded` values in devtools, and compare that output against the source right next to it. Use them to confirm your own markup matches before you start layering custom CSS on top.

Anatomy

Accordion composes an Accordion root around one or more AccordionItem elements, each holding an AccordionHeader/AccordionTrigger pair and an AccordionContent panel; the item's `value` prop is what open state actually tracks. Collapsible is flatter — just Collapsible, CollapsibleTrigger, and CollapsibleContent — because there's only ever one region, so there's no item wrapper or `value` to assign.

State model

Accordion runs in one of two modes: `type="single"` (the default) tracks a single open `value` string, while `type="multiple"` tracks a `string[]`. Both accept `value`/`onValueChange` for controlled use or `defaultValue` for uncontrolled use, plus `collapsible` (whether the last open item in single mode can close) and `loop` for keyboard wraparound. Collapsible needs none of that type juggling — it's just `open`/`defaultOpen`/`onOpenChange` as a plain boolean.

Keyboard and accessibility

Triggers in both components carry `role="button"` semantics with `aria-expanded` and `aria-controls`, and respond to Enter or Space to toggle open state — behavior the `COLLAPSIBLE_A11Y_CONTRACT` and `ACCORDION_A11Y_CONTRACT` constants codify directly. Accordion goes a step further, wrapping its panels in `role="region"` and giving triggers arrow-key roving focus governed by `orientation` and `loop`, since a set of triggers benefits from list-style navigation between them. Collapsible skips that roving-focus layer entirely, since managing a single trigger leaves nothing to navigate across.

Styling and tokens

Both families expose `data-slot`, `data-state`, and `data-disabled` (Accordion adds `data-orientation`) so CSS can target open, closed, and disabled states without touching JavaScript. Content unmounts when closed by default in both; pass `forceMount` on AccordionContent or CollapsibleContent if you need the panel present in the DOM to drive a height-based CSS transition.

API

AccordionItem takes a required `value` plus `disabled`; AccordionTrigger takes the same button-like props as other interactive primitives, including `asChild`. Collapsible's root takes `open`, `defaultOpen`, `onOpenChange`, and `disabled` — there's no `type` prop because it never tracks more than one boolean, unlike Accordion.

Edge cases

With `collapsible={false}` (the default for single-type Accordion), at least one item always stays open, so don't build a "collapse all" affordance against that configuration. `disabled` on an AccordionItem blocks its trigger but leaves the item in the DOM, so a screen reader user still encounters it — if every item ends up disabled, consider hiding the whole accordion instead of leaving a fully inert one on screen.

See Headless versus Themed for how the `@askrjs/ui`/`@askrjs/themes` split works in general, and Focus and Dismissal for the keyboard and focus utilities both primitives are built on. The Combobox and Command page covers a different disclosure shape if what you actually need is a filterable list rather than a static one.