Accordion
A vertically stacked set of interactive headings that each reveal a section of content.
Yes. It adheres to the WAI-ARIA design pattern and is keyboard navigable.
Yes. It comes with default styles that match the other components' aesthetic.
Yes. It's animated by default, with a CSS keyframe you can disable.
/** @jsxImportSource @bext-stack/framework */
// src/components/ui/accordion.tsx — driven by the island (data-ui="accordion-trigger")
export function Accordion(o) {
const rows = o.items.map((it) => \`<div data-ui="accordion-item" class="border-b">
<button data-ui="accordion-trigger" data-state="closed" class="flex w-full items-center justify-between py-4 text-sm font-medium hover:underline">
\${it.trigger}<span class="ui-acc-chevron transition-transform"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"/></svg></span>
</button>
<div data-ui="accordion-content" hidden class="text-sm"><div class="pb-4 text-muted-foreground">\${it.content}</div></div></div>\`).join("");
return \`<div data-ui="accordion" class="w-full \${o.class || ""}">\${rows}</div>\`;
}
Installation
$ bext ui add accordion
Copy and paste the following into src/components/ui/accordion.tsx.
/** @jsxImportSource @bext-stack/framework */
// src/components/ui/accordion.tsx — driven by the island (data-ui="accordion-trigger")
export function Accordion(o) {
const rows = o.items.map((it) => \`<div data-ui="accordion-item" class="border-b">
<button data-ui="accordion-trigger" data-state="closed" class="flex w-full items-center justify-between py-4 text-sm font-medium hover:underline">
\${it.trigger}<span class="ui-acc-chevron transition-transform"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"/></svg></span>
</button>
<div data-ui="accordion-content" hidden class="text-sm"><div class="pb-4 text-muted-foreground">\${it.content}</div></div></div>\`).join("");
return \`<div data-ui="accordion" class="w-full \${o.class || ""}">\${rows}</div>\`;
}
This component is interactive — make sure the shared island is loaded (see Islands). It reacts to data-ui="accordion" hooks.
On This Page