Skip to main content
xriptxr

Accordion

Info:Layout
27

A stack of collapsible sections, one or many open at a time, driven by pointer or keyboard.

collapse expander disclosure faq collapsible sections

Live demo

live · @xtyle/astro

Accordion

Single-open

What's your shipping time?

Orders placed before 2pm ship the same business day; everything else ships the next morning.

How do returns work?

Unworn items are accepted within 30 days for a full refund — no restocking fee, no questions asked.

Is there a warranty?

Every piece is covered against manufacturing defects for one year from the delivery date.

Rich headers · nested components

Settings Info:3

A panel is a full render slot, so components nest inside it.

Including ones with their own chrome.

Saved

Headers carry markup too, not just text.

Multiple open · compact

Availability

In stock, on sale, free shipping.

Sort

Price, rating, newest first.

Saved searches

Sign in to save a search.

A different marker

What is a marker glyph?

Any name the icon roster can draw, so a mod that fills xtyle.icons can supply its own and name it here.

Does it stay themed?

Yes. The glyph inherits the derived color like every other icon.

Accordion stacks a set of disclosure sections that expand and collapse. Each section pairs a [slot="header"] header with the [slot="panel"] that follows it; the component wraps every header in a heading and a role="button" trigger carrying aria-expanded and aria-controls, and turns each panel into a labelled role="region" that hides when collapsed.

By default it is single-open: opening one section closes the rest. multiple lets several stay open at once. Mark a header open to expand its section initially, or disabled to lock it. The heading level is h3 by default and settable with headingLevel, and three sizes (sm, md, lg) scale the trigger density. A chevron rotates with the open state, and pointer, Enter/Space, and the arrow/Home/End keys all drive it.

When to use

How this component composes with the rest of the set.

Pair headers and panels in order (a [slot="header"] followed by its [slot="panel"]) and repeat for each section.
The slotted form is for raw HTML and Astro; under Astro use the data-xtyle-header / data-xtyle-panel markers, because its named-slot handling consumes slot before the element sees it. @xtyle/svelte takes its sections as data instead — a sections array and a panel snippet — and renders the pairs itself, so slotted children handed to it are not read.
Leave multiple off for an FAQ where one answer shows at a time; turn it on for independent filter or settings groups.
For a small fixed set of mutually exclusive views with their own content area, reach for Tabs instead.

Props

6 props, straight from the manifest.

PropTypeDefaultBindingsDescription
items AccordionSection[]
html astro
The sections as data instead of authored [slot="header"] / [slot="panel"] pairs: an array of { value, header, body?, disabled? }, serialized to JSON on the attribute. The Svelte binding spells the same list sections and takes its bodies from a panel snippet.
sections AccordionSection[]
svelte
Svelte only: the sections as data, with each panel rendered by the panel snippet keyed by value. The same list is items on every other binding.
multiple boolean false
html svelte astro
Allows several sections to stay open at once; when off, opening one closes the others.
size Size
sm md lg
md
html svelte astro
Trigger density: sm, md, or lg.
headingLevel html: heading-level 2 | 3 | 4 | 5 | 6 3
html svelte astro
The heading level wrapping each trigger, so the accordion sits correctly in the document outline.
chevronIcon html: chevron-icon string "chevron-down"
html svelte astro
The roster glyph drawn as the disclosure marker. Any name the icon roster can draw, including one a mod contributed through the xtyle.icons slot.

Events

What the component emits, and what rides along on event.detail. The name in the first column is the one addEventListener takes.

EventDetailBindingsDescription
toggle { value, open, values }
html svelte astro
A section opened or closed.

Appearance

Sizes

sm

.xtyle-accordion--sm

Compact triggers.

md

default
.xtyle-accordion

Default.

lg

.xtyle-accordion--lg

Roomy triggers.

States

open

.xtyle-accordion__trigger[aria-expanded="true"]

An expanded section: the trigger reads aria-expanded="true" and the chevron rotates.

trigger-hover

.xtyle-accordion__trigger:hover

Pointer over a header: the hover tint paints behind it.

trigger-focus-visible

.xtyle-accordion__trigger:focus-visible

Keyboard focus on a header: an inset token ring plus the transparent outline promoted in forced-colors mode.

disabled

.xtyle-accordion__trigger:disabled

A locked header: muted and non-interactive.

Anatomy

The named parts that make up the component. A ::part() handle is reachable from your own stylesheet; the class beside it is the component's internal selector, which a shadow boundary keeps to itself.

accordion

Success:::part(accordion) .xtyle-accordion

The bordered container stacking the sections, with hairlines between them.

--font-sans --fg-0 --bg-1 --border-thin --line --radius-md

trigger

Success:::part(trigger) .xtyle-accordion__trigger

The full-width <summary> that toggles its section; carries the hover/press overlay. The native disclosure marker is suppressed in favor of the chevron.

--text-body --weight-medium --leading-tight --fg-0 --space-3 --space-4 --state-hover --state-press --border-normal --border-thick --ring --fg-disabled --duration-fast --ease-standard

chevron

Success:::part(chevron) .xtyle-accordion__chevron

The disclosure caret in the trigger corner; rotates 180° when the section is open. It is an <xtyle-icon name="chevron-down"> inside the accordion's fragment, so the glyph renders through the Icon component and a mod can swap it without touching the accordion.

--fg-2 --duration-fast --ease-standard

panel

Success:::part(panel) .xtyle-accordion__panel

The collapsible role="region" holding the section content; the enclosing <details> collapses it, so it carries no hidden of its own.

--fg-1 --space-1 --space-4 --text-body --leading-normal

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 27/27 consumed tokens produced default register: 310 tokens

Live coverage check against the xtyle-default register (derive(xtyleDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--bg-1 --border-normal --border-thick --border-thin --duration-fast --ease-standard --fg-0 --fg-1 --fg-2 --fg-disabled --font-sans --leading-normal --leading-tight --line --radius-md --ring --space-1 --space-2 --space-3 --space-4 --space-5 --state-hover --state-press --text-body --text-lg --text-sm --weight-medium

Slots

header
html svelte astro

Each section's header label, marked slot="header" or data-xtyle-header; add open to expand it initially or disabled to lock it. Astro consumes slot to route children, so use data-xtyle-header there. Carries markup, not just text: an icon, a badge, and nested components all survive into the render, including the static one.

panel
html svelte astro

Each section's collapsible content, marked slot="panel" or data-xtyle-panel (use data-xtyle-panel under Astro), paired to the header before it by order. A full render slot: nested components keep working, and under Astro the pairing resolves at build time so the sections are complete before any script runs.

Accessibility

Each section is a native <details>/<summary> disclosure, so it opens and closes with the runtime never loading and the browser announces the expanded state itself rather than a hand-maintained aria-expanded.
The summary holds a heading (h3 by default, set with headingLevel) so the sections still land in the document outline and screen-reader rotor.
Single-open mode gives every section a shared name, which is what makes opening one collapse the rest; the browser enforces it, with no script involved. Under multiple the grouping is dropped.
The panel is a role="region" wired back with aria-labelledby; it never carries hidden, because the disclosure already owns its own visibility.
Pointer, Enter, and Space toggle a section; Up/Down arrows move focus between headers and Home/End jump to the first and last.
A header marked disabled is skipped by the arrow keys and cannot toggle. <summary> has no native disabled state, so it is aria-disabled and the toggle is cancelled; it stays focusable, which is the ARIA-preferred treatment.
Focus on a header shows an inset token ring plus a transparent outline the forced-colors base rule promotes to a real system outline.

Code

Single-open FAQ

Three sections where opening one collapses the others; the second starts open.

<xtyle-accordion>
	<span slot="header">Shipping</span>
	<div slot="panel">Orders ship within two business days.</div>
	<span slot="header" open>Returns</span>
	<div slot="panel">Unworn items are accepted within 30 days.</div>
	<span slot="header">Warranty</span>
	<div slot="panel">Covered against defects for one year.</div>
</xtyle-accordion>

Multiple open, with a disabled section

A compact accordion that lets several panels stay open, with one locked header.

<xtyle-accordion multiple size="sm">
	<span slot="header" open>Filters</span>
	<div slot="panel">In stock, on sale, free shipping.</div>
	<span slot="header" open>Sort</span>
	<div slot="panel">Price, rating, newest.</div>
	<span slot="header" disabled>Saved searches</span>
	<div slot="panel">Sign in to save a search.</div>
</xtyle-accordion>

Sections as data

The same accordion declared as a list instead of authored pairs. The attribute takes JSON, the Astro binding takes the array, and the Svelte binding spells it sections with a panel snippet.

<xtyle-accordion items='[
	{ "value": "shipping", "header": "Shipping", "panel": "Orders ship within two business days." },
	{ "value": "returns", "header": "Returns", "panel": "Unworn items are accepted within 30 days.", "open": true }
]'></xtyle-accordion>

A different marker glyph

The disclosure marker drawn from any name the icon roster can draw, including one a mod contributed.

<xtyle-accordion chevron-icon="plus">
	<span slot="header">What is a marker glyph?</span>
	<div slot="panel">Any name the icon roster can draw.</div>
	<span slot="header">Can a mod add one?</span>
	<div slot="panel">Yes, by filling the <code>xtyle.icons</code> slot.</div>
</xtyle-accordion>