Accordion

A hand-drawn accordion of collapsible sections (disclosure pattern).

Overview

An Accordion stacks collapsible sections so people can expand just the content they need. Use type="single" to keep at most one section open (like an FAQ), or type="multiple" to let several stay open at once.

Anatomy

A vertical stack of sketchy boxes (@ghds/sketch-core), each with a header button (aria-expanded, aria-controls) and a collapsible role="region". The header’s chevron rotates when open. The API is data-driven — pass an items array of { value, label, content }. Open state is a set of values (string[]), controlled or uncontrolled.

Variants & States

State Status Notes
Collapsed Implemented Default; content hidden, aria-expanded=false.
Expanded Implemented Content revealed, chevron rotated, aria-expanded=true.
Single vs multiple Implemented type controls whether one or many can be open.
Disabled Implemented Per-item; header not togglable and skipped by arrow keys.

Usage

Do

  • Use single mode for mutually-exclusive content (FAQs); multiple when sections are independent.
  • Write concise, scannable header labels.
  • Keep it controlled (value + onValueChange) if open state must sync with other UI.

Don't

  • Don't hide critical content behind an accordion that users must see.
  • Don't nest accordions deeply — it buries content.

Accessibility

Key Action
Enter / Space Toggle the focused section.
Arrow Up / Down Move focus to the previous / next header (wraps).
Home / End Move focus to the first / last header.

Content

A short header label per section and the revealed content. Content is a ReactNode on React/React Native; on Web Components it is section text (content string).

Props API

React@ghds/react

PropTypeDefaultDescription
itemsAccordionItem[]{ value, label, content, disabled? } per section.
type'single' | 'multiple''single'How many sections may be open.
valuestring[]Controlled set of open values.
defaultValuestring[]Initial open values when uncontrolled.
onValueChange(values: string[]) => voidFires when the open set changes.

Web Components@ghds/web-components

PropTypeDefaultDescription
itemsGhAccordionItemData[]{ value, label, content?: string, disabled? } (property).
type'single' | 'multiple''single'How many sections may be open.
valuestring[]Controlled set of open values (property).
value-change eventCustomEvent<string[]>Dispatched with the open set.

React Native@ghds/react-native

PropTypeDefaultDescription
itemsAccordionItem[]{ value, label, content, disabled? } per section.
type'single' | 'multiple''single'How many sections may be open.
valuestring[]Controlled set of open values.
defaultValuestring[]Initial open values when uncontrolled.
onValueChange(values: string[]) => voidFires when the open set changes.
testIDstringTest handle for queries.

Code examples

// React — @ghds/react
import { Accordion } from '@ghds/react/accordion';

<Accordion
  type="single"
  defaultValue={['shipping']}
  items={[
    { value: 'shipping', label: 'Shipping', content: <p>Ships in 2–3 business days.</p> },
    { value: 'returns', label: 'Returns', content: <p>Free returns within 30 days.</p> },
  ]}
/>;
<!-- Web Components — @ghds/web-components -->
<script type="module">
  import '@ghds/web-components/accordion';
  const el = document.getElementById('acc');
  el.type = 'single';
  el.value = ['shipping'];
  el.items = [
    { value: 'shipping', label: 'Shipping', content: 'Ships in 2–3 business days.' },
    { value: 'returns', label: 'Returns', content: 'Free returns within 30 days.' },
  ];
  el.addEventListener('value-change', (e) => {
    el.value = e.detail;
  });
</script>
<gh-accordion id="acc"></gh-accordion>
// React Native — @ghds/react-native
import { Accordion } from '@ghds/react-native/accordion';
import { Text } from '@ghds/react-native/theme';

<Accordion
  type="single"
  items={[{ value: 'shipping', label: 'Shipping', content: <Text>Ships in 2–3 days.</Text> }]}
/>;

Live Demo

React @ghds/react

Web Components @ghds/web-components