Skip to main content

Accordion

Groups related content into collapsible sections to reduce visual complexity. Use when page content can be meaningfully chunked into distinct sections. Don't use when all sections need to be visible simultaneously.

OverviewStyleAccessibility

Description

Anatomy

PartRequired?Notes
Trigger / Header Required Clickable row containing the section label and expand/collapse indicator. Must be a focusable, keyboard-operable element. Minimum touch target 44x44px.
Indicator icon Required Chevron or plus/minus icon that rotates or toggles to signal the open/closed state. Should be decorative (aria-hidden) since state is conveyed via aria-expanded.
Content panel Required The collapsible region. Hidden via display:none or height:0 when collapsed; fully visible and in the tab order when expanded.
Divider Recommended Horizontal rule between accordion items. Provides visual separation without adding spacing overhead. Uses --op-color-border-default.
Section label Required Plain-language title describing the section contents. Should be short enough to read at a glance — aim for under 60 characters.
Supporting metadata (badge, count) Optional Secondary information displayed inline with the header, such as an item count or status badge. Does not replace the section label.

Variants

States

State Behaviour
Collapsed (default) Content panel is hidden. Trigger displays the section label and a downward-pointing chevron. aria-expanded='false' on the trigger.
Expanded Content panel is visible and participates in tab order. Chevron rotates 180deg (or switches to minus icon). aria-expanded='true' on the trigger.
Focus 3px focus ring using --op-color-interactive-focus appears around the trigger. Visible on keyboard navigation and pointer focus (unless :focus-visible is scoped).
Hover Trigger background shifts to --op-color-bg-subtle. Cursor changes to pointer. No delay.
Disabled Trigger is non-interactive. Opacity reduced to 40%. aria-disabled='true'. Do not use disabled accordions to hide required information — consider using a loading state or conditional rendering instead.
Loading Content panel shows a skeleton or spinner while async content resolves. Trigger remains interactive. Announce load completion to screen readers via aria-live region if content changes after initial render.

Usage guidelines

Do / Don't

Do

Write trigger labels as plain-language nouns or short phrases ('Contact details', 'Submission history') that accurately describe what is inside.

Don't

Use vague labels like 'More information' or 'Details' that don't help users decide whether to expand.

Do

Default the most commonly needed section to open if you know the user's primary task.

Don't

Default all sections to open — that defeats the purpose of the pattern.

Do

Keep content panel contents concise. If a panel contains more than a screenful of content, consider splitting it into separate pages or sub-sections.

Don't

Nest accordions inside accordion panels. This creates orientation problems and is difficult to navigate with a keyboard.

Do

Use consistent indicator icons across all accordion instances on the same page.

Don't

Mix chevron and plus/minus icons on the same page or within the same accordion group.

Layout & Spacing

Trigger padding: --op-space-16 (16px) vertical, --op-space-20 (20px) horizontal Content panel padding: --op-space-8 (8px) top, --op-space-20 (20px) right/bottom/left Gap between accordion items (flush variant): 0 — divider handles separation Gap between accordion items (bordered variant): --op-space-8 (8px) Indicator icon size: 20x20px, margin-left: --op-space-12 (12px) from label Minimum trigger height: 44px (touch target compliance)

Tokens

PartTokenValue
Trigger background (default) --op-color-bg-primary White on standard page canvas
Trigger background (hover) --op-color-bg-subtle Light grey on hover
Trigger label text --op-color-text-primary High-contrast body text
Indicator icon --op-color-text-secondary Slightly muted to de-emphasise the affordance vs the label
Divider --op-color-border-default Between items and below expanded content panels
Content panel background --op-color-bg-primary Same as trigger to maintain a flat appearance
Content panel text --op-color-text-primary Standard body copy
Focus ring --op-color-interactive-focus 3px solid, offset 2px, on trigger element
Disabled trigger text --op-color-text-disabled 40% opacity overlay acceptable as alternative
Bordered variant border --op-color-border-default 1px solid, radius --op-radius-md (8px)

Engineering notes

  • The wa-accordion / wa-accordion-item web components (Web Awesome) are the recommended base. Each item ships with the correct ARIA pattern (heading-wrapped button[aria-expanded] + panel) and handles animation via the --show-duration and --hide-duration CSS custom properties.
  • For multi-expand groups, use the default mode='multiple' on wa-accordion. For single-expand (exclusive) groups, set mode='single' (or 'single-collapsible' if the group should also allow zero items open) — this is built into the component and needs no custom event wiring.
  • Do not use the HTML
    / element directly — browser default styling is inconsistent and the animation cannot be controlled without JavaScript hacks.
  • Lazy-load heavy content panels (e.g. data tables, maps) by listening for the 'wa-expand' event on the wa-accordion and fetching content only when the matching panel first opens (event.detail.item identifies which item triggered it).
  • Respect prefers-reduced-motion: set --show-duration: 0ms and --hide-duration: 0ms on wa-accordion-item in a @media (prefers-reduced-motion: reduce) block.
  • If an accordion item should open based on a URL hash (deep link to a section), read location.hash on page load and programmatically set expanded on the matching wa-accordion-item element.
  • Use expandAll() / collapseAll() methods on wa-accordion for 'expand all' / 'collapse all' controls. expandAll() is a no-op when mode is single or single-collapsible.

Keyboard interaction

KeyAction
Tab Moves focus to the next accordion trigger (or next focusable element outside the accordion). When a panel is expanded, Tab also cycles through interactive elements inside the panel.
Shift+Tab Moves focus to the previous accordion trigger or focusable element.
Enter Toggles the focused trigger open or closed.
Space Toggles the focused trigger open or closed (same as Enter).
Home Moves focus to the first accordion trigger in the group (if group keyboard navigation is implemented).
End Moves focus to the last accordion trigger in the group (if group keyboard navigation is implemented).

Why it matters

Government services are required to meet WCAG 2.1 AA. Many stakeholders and community members using Open Point and Social Point rely on keyboard navigation or screen readers — including older users, users with motor impairments, and users in low-bandwidth environments using assistive technology. Accordions are a common source of accessibility failures when the trigger is not a real button or when state is conveyed only visually.

Focus

Focus is placed on the trigger button when it receives keyboard or pointer focus. When a panel opens, focus remains on the trigger — do not move focus into the panel automatically. When a panel closes, focus remains on the trigger. All interactive elements inside an expanded panel are reachable via Tab in DOM order. Collapsed panels must remove their content from the tab order (use display:none or visibility:hidden, not opacity:0 or height:0 alone).

ARIA

Role or attributeWhen to useExample
aria-expanded Applied to the trigger button. Set to 'true' when the panel is open, 'false' when closed. <button aria-expanded="true" aria-controls="panel-1">Submission history</button>
aria-controls Links the trigger button to its controlled panel by ID. <button aria-controls="panel-submission-history">Submission history</button>
id (panel) Unique ID on the content panel element, referenced by aria-controls on the trigger. <div id="panel-submission-history" role="region" aria-labelledby="trigger-submission-history">
role="region" Applied to the content panel when the accordion group has more than 6 items. Omit for smaller groups to avoid cluttering the landmark list. <div role="region" aria-labelledby="trigger-1">
aria-labelledby (panel) Points from the content panel back to its trigger, giving the region an accessible name. <div role="region" aria-labelledby="trigger-submission-history">
aria-disabled Used on trigger buttons that are intentionally non-interactive. Does not prevent focus — use in addition to visual disabled styling. <button aria-disabled="true">Billing (not available)</button>

Contrast

Trigger label text (--op-color-text-primary on --op-color-bg-primary): meets 4.5:1 AA for normal text. Trigger label text on hover (--op-color-text-primary on --op-color-bg-subtle): verify contrast ratio when customising --op-color-bg-subtle; must remain >= 4.5:1. Indicator icon (--op-color-text-secondary): icon is decorative (aria-hidden); contrast requirement does not apply, but should be >= 3:1 against background for users who may still perceive it as meaningful. Focus ring (--op-color-interactive-focus): 3px solid ring with 2px offset must achieve 3:1 contrast against both the trigger background and the surrounding page background per WCAG 2.1 SC 1.4.11. Disabled state: --op-color-text-disabled on --op-color-bg-primary should be presented as truly non-interactive; if contrast falls below 4.5:1, this is acceptable per WCAG exception for disabled components, but ensure the disabled state is clearly communicated by more than colour alone.

Touch targets

The trigger row must have a minimum height of 44px and span the full width of its container. Do not restrict the clickable area to just the label text or the icon. On mobile viewports, verify that the trigger height does not collapse below 44px when the label wraps to two lines.

Things to avoid

  • Using colour alone to indicate expanded/collapsed state — always pair with an icon change (chevron rotation or plus/minus swap) and aria-expanded.
  • Animating the panel open/close without respecting prefers-reduced-motion.
  • Nesting accordions — creates navigation confusion for keyboard and screen reader users.
  • Auto-collapsing a panel the user has opened in response to a page event they did not initiate.
  • Placing critical error messages or required form fields inside a collapsed panel by default — users may not discover them.

Was this page helpful?

Updated 5 October 2026