Vertical list of expandable disclosure items, each header wired to its panel with aria-expanded / aria-controls.
Single-open by default; opt into multi-open via allowMultiple
First item auto-expanded unless collapsedByDefault is set
Surface-aware typography and borders (pixel vs linear)
aria-expanded + aria-controls wired per header for assistive tech
SSR-safe and tree-shakable; unopened panels are not rendered
Status
stable
Category
navigation
Since
v1.0.0
API
import { PixelAccordion } from '@pxlkit/ui-kit';
Prop
Type
Default
Description
items* (required)
AccordionItem[]
—
Accordion items rendered in order. First item is expanded by default.
allowMultiple
boolean
false
When true, multiple items can be expanded simultaneously.
collapsedByDefault
boolean
false
When set, no item is initially expanded. Defaults to expanding the first.
surface
'pixel' | 'linear'
—
Visual surface treatment override.
ref points to <div>.
Accessibility
WCAG target: 2.1 AA
disclosure
Each header is a native <button> with aria-expanded reflecting open state and aria-controls pointing at the panel id. Expanded panels are plain containers that follow their header in reading order — no role="region", which would proliferate landmarks (and collide when several accordions share titles), and so no name, which ARIA does not allow on an element without a role — matching the WAI-ARIA disclosure pattern stacked into an accordion. On the pixel surface a header shows keyboard focus inside its item, whose cut corners would clip a ring.
Keyboard
Key
Action
When
Enter
Toggles the focused item open or closed
—
Space
Toggles the focused item open or closed
—
Tab
Moves focus between item headers
—
Usage
import { PixelAccordion } from '@pxlkit/ui-kit';
const SAMPLE_ITEMS = [
{
id: 'overview',
title: 'Overview',
content: 'Introductory section that opens by default.',
},
{
id: 'details',
title: 'Details',
content: 'Secondary section with extended copy.',
},
{
id: 'faq',
title: 'FAQ',
content: 'Common questions and short answers.',
},
];
export function Default() {
return <PixelAccordion items={SAMPLE_ITEMS} />;
}
Examples
Default
import { PixelAccordion } from '@pxlkit/ui-kit';
const SAMPLE_ITEMS = [
{
id: 'overview',
title: 'Overview',
content: 'Introductory section that opens by default.',
},
{
id: 'details',
title: 'Details',
content: 'Secondary section with extended copy.',
},
{
id: 'faq',
title: 'FAQ',
content: 'Common questions and short answers.',
},
];
export function Default() {
return <PixelAccordion items={SAMPLE_ITEMS} />;
}
Collapsed by default
import { PixelAccordion } from '@pxlkit/ui-kit';
const SAMPLE_ITEMS = [
{
id: 'overview',
title: 'Overview',
content: 'Introductory section that opens by default.',
},
{
id: 'details',
title: 'Details',
content: 'Secondary section with extended copy.',
},
{
id: 'faq',
title: 'FAQ',
content: 'Common questions and short answers.',
},
];
export function CollapsedByDefault() {
return <PixelAccordion items={SAMPLE_ITEMS} collapsedByDefault />;
}
Allow multiple
import { PixelAccordion } from '@pxlkit/ui-kit';
const SAMPLE_ITEMS = [
{
id: 'overview',
title: 'Overview',
content: 'Introductory section that opens by default.',
},
{
id: 'details',
title: 'Details',
content: 'Secondary section with extended copy.',
},
{
id: 'faq',
title: 'FAQ',
content: 'Common questions and short answers.',
},
];
export function AllowMultiple() {
return <PixelAccordion items={SAMPLE_ITEMS} allowMultiple />;
}
Surfaces
import { PixelAccordion } from '@pxlkit/ui-kit';
const SAMPLE_ITEMS = [
{
id: 'overview',
title: 'Overview',
content: 'Introductory section that opens by default.',
},
{
id: 'details',
title: 'Details',
content: 'Secondary section with extended copy.',
},
{
id: 'faq',
title: 'FAQ',
content: 'Common questions and short answers.',
},
];
export function Surfaces() {
return (
<div className="flex flex-col gap-4">
<PixelAccordion items={SAMPLE_ITEMS} surface="pixel" />
<PixelAccordion items={SAMPLE_ITEMS} surface="linear" />
</div>
);
}