Skip to content

HyAccordion ​

Usage examples on this page are written for Lit / plain HTML (<hy-accordion>). The same component ships as HyAccordion in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

An accordion component using CSS Grid animation for smooth expand/collapse transitions.

CSS Grid Animation Approach ​

This implementation uses CSS Grid's grid-template-rows property to create smooth expand/collapse animations:

  • Collapsed State: grid-template-rows: 0fr (zero height)
  • Expanded State: grid-template-rows: 1fr (content height)
  • Browser Handled: Height calculations are managed by the browser
  • Content Adaptive: Automatically adjusts when content changes
  • Clean Implementation: No JavaScript height measurements required

Technical Benefits ​

  • Eliminates need for ResizeObserver height tracking
  • No manual animation frame management
  • Automatic content size adaptation
  • Smooth CSS transitions
  • Reduced code complexity

Accessibility: built in ​

  • Full keyboard navigation (Enter/Space to toggle, Tab to focus)
  • Collapsed content is inert (and aria-hidden): its focusable children leave the Tab order until the accordion expands
  • ARIA live regions for screen reader announcements
  • Proper ARIA attributes and relationships
  • High contrast mode support
  • Reduced motion support with instant transitions
  • Visible focus indicators

Browser Compatibility ​

CSS Grid animation is supported in:

  • Chrome 57+ (March 2017)
  • Firefox 52+ (March 2017)
  • Safari 10.1+ (March 2017)
  • Edge 16+ (October 2017)

Icons ​

The prefix icon and the expand indicator are names (prefix-icon-name, icon-name) from the design system's icon family. The React HyAccordion takes the same two properties as nodes (HyIcon has no name lookup).

When to use

  • Sections people open only when they need them: an FAQ, advanced settings, optional details.
  • A long page where showing every section at once would bury the one people want.

Do

  • Title each section so people know what is inside without opening it.
  • Open the section most people need first with expanded.

When not to use

  • Content every reader needs: show it on the page under headings, or group it in a hy-card.
  • A single short section: show it without a disclosure.
  • Sections nested more than one level deep: hy-tree.
  • Collapsible groups of navigation links: hy-sidebar-group.
  • Switching between peer views of the same content: hy-tab-group.

Examples ​

Basic Usage ​

html
<hy-accordion label="Settings" expanded>
  <p>Configure your application settings here.</p>
</hy-accordion>

Flat / borderless presentation (emphasis="plain") ​

html
<hy-accordion emphasis="plain" label="Neutral">
  <p>
    Chromeless header — no box, no border, no radius. Add a `border-block-end` rule consumer-side
    for a section divider.
  </p>
</hy-accordion>

With All Features ​

html
<hy-accordion
  label="Email Settings"
  subtitle="Configure notifications and preferences"
  optional-text="Last updated today"
  prefix-icon-name="mail"
  size="medium"
  announce-state-changes="true"
  animation-duration="400"
>
  <div>
    <h3>Notification Settings</h3>
    <p>Choose how you want to receive notifications.</p>
  </div>
</hy-accordion>

Programmatic Control ​

html
<hy-accordion id="myAccordion" label="API Example">
  <p>Content that can be controlled via JavaScript.</p>
</hy-accordion>

<script>
  const accordion = document.getElementById('myAccordion');

  // Listen for state changes
  accordion.addEventListener('toggle', (e) => {
    console.log('State changed:', e.detail.expanded);
  });

  // Programmatic control
  accordion.expand(); // Expand with animation
  accordion.collapse(); // Collapse with animation
  accordion.toggle(); // Toggle current state
</script>

Custom Animation Timing ​

You can customize animation via CSS custom properties:

css
hy-accordion {
  --hy-accordion-motion-transition-expand-duration: 500ms;
  --hy-accordion-motion-transition-expand-easing: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
headerIdheader-idstring''Auto-generated unique identifier for the header button element. Used to establish ARIA relationships between header and content.
contentIdcontent-idstring''Auto-generated unique identifier for the content region element. Used to establish ARIA relationships between header and content.
labellabelstring'Accordion Title'The heading text displayed in the accordion header. Appears alongside prefix and optional text, properly aligned with the expand/collapse icon.
subtitlesubtitlestring''Secondary descriptive text displayed below the main title. Provides additional context with smaller, lighter typography.
optionalTextoptional-textstring''Brief supplementary text displayed after the main title. Useful for status indicators, timestamps, or brief metadata. Uses smaller, muted styling and prevents line wrapping.
sizesize'small' | 'medium' | 'large''medium'Size variant that controls typography, spacing, and visual hierarchy. - small: Compact presentation with reduced spacing - medium: Standard size for most use cases (default) - large: Prominent display with increased spacing
emphasisemphasis'solid' | 'outlined' | 'tinted' | 'plain''solid'Visual chrome weight — solid (default) / outlined / tinted / plain. - solid: surface fill + border + radius (the historic baseline — unchanged) - outlined: transparent fill, keep the border - tinted: subtle surface fill, no border - plain: chromeless (no fill, no border) — the flat / borderless presentation (industry "ghost"; flush also removes the inset); add a border-block-end rule consumer-side for a section divider.
flushflushbooleanfalseRemoves the accordion's inset: the header's inline padding and the body's padding, so the title and the content line up with the container's edge — for an accordion set inside a panel or a list that already draws its own inset (Carbon's flush alignment, Bootstrap's accordion-flush). Usually with emphasis="plain".
expandedexpandedbooleanfalseWhether the accordion is currently expanded (content visible) or collapsed (content hidden). Changes trigger CSS Grid-based animations. Reflected as an attribute for CSS styling and external state queries.
disableddisabledbooleanfalseDisables all accordion interactions and applies disabled styling. When disabled, interactions are prevented and visual styling indicates disabled state.
animationDurationanimation-durationnumber300Duration in milliseconds for CSS Grid expand/collapse animations. Controls the transition speed of the grid-template-rows animation.
prefixIconNameprefix-icon-namestring | undefined—Icon name for the prefix indicator displayed before the title, from the design system's icon family. The React HyAccordion takes the same property as a node.
iconNameicon-namestring'chevron-down'Icon name for the expand/collapse indicator, from the design system's icon family. The icon rotates 180 degrees when the accordion expands. The React HyAccordion takes the same property as a node.
announceStateChangesannounce-state-changesbooleantrueWhether to announce state changes to screen readers via ARIA live regions. Uses optimized timing for compatibility with different screen readers.
announcementPriorityannouncement-priority'polite' | 'assertive''polite'ARIA live region politeness level for screen reader announcements. - polite: Announcements wait for current reading to complete (recommended) - assertive: Announcements interrupt current reading
expandedLabelexpanded-labelstring'{label} expanded'The announcement read when the accordion expands; {label} is the header text. Use for internationalization.
collapsedLabelcollapsed-labelstring'{label} collapsed'The announcement read when the accordion collapses; {label} is the header text. Use for internationalization.

Events ​

EventDetailDescription
toggle—Fired when the accordion state changes (expand or collapse). Detail: { expanded: boolean }
expand—Fired specifically when the accordion expands. Detail: { expanded: boolean }
collapse—Fired specifically when the accordion collapses. Detail: { expanded: boolean }
transition-end—Fired when the CSS Grid animation completes. Detail: { expanded: boolean }

Slots ​

SlotDescription
defaultThe main content displayed when the accordion is expanded

CSS Parts ​

PartDescription
baseThe accordion's root container element
headerThe clickable header button element
prefixThe prefix icon container (only present when prefix content exists)
iconThe expand/collapse icon container
contentThe CSS Grid animated content container
live-regionThe ARIA live region for screen reader announcements (visually hidden)

CSS Custom Properties ​

The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.

PropertyDefaultDescription
--hy-accordion-border-default-restvar(--hy-border-default-rest)Border color at rest
--hy-accordion-border-subtle-restvar(--hy-border-subtle-rest)Subtle border color
--hy-accordion-stroke-smvar(--hy-stroke-sm)Border width
--hy-accordion-radius-row-list-mdvar(--hy-radius-row-list-md)Border radius where the accordion rounds all four corners at once (the per-corner hooks below shape the expanded header)
--hy-accordion-radius-row-list-md-top-startvar(--hy-radius-row-list-md-top-start)Top-start corner radius override.
--hy-accordion-radius-row-list-md-top-endvar(--hy-radius-row-list-md-top-end)Top-end corner radius override. See top-start.
--hy-accordion-header-padding-row-list-md-blockvar(--hy-padding-row-list-md-block)Header block padding
--hy-accordion-header-padding-row-list-sm-blockvar(--hy-padding-row-list-sm-block)Header block padding
--hy-accordion-header-padding-row-list-lg-blockvar(--hy-padding-row-list-lg-block)Header block padding
--hy-accordion-padding-layout-2xlvar(--hy-padding-layout-2xl)Inline padding
--hy-accordion-padding-layout-nonevar(--hy-padding-layout-none)Inset when flush: the header's sides and the body's padding
--hy-accordion-gap-row-list-sm-blockvar(--hy-gap-row-list-sm-block)Gap for small size
--hy-accordion-gap-row-list-md-blockvar(--hy-gap-row-list-md-block)Gap for medium size
--hy-accordion-gap-row-list-lg-blockvar(--hy-gap-row-list-lg-block)Gap for large size
--hy-accordion-gap-row-list-md-inlinevar(--hy-gap-row-list-md-inline)Gap between header elements
--hy-accordion-text-transformnoneText transform for accordion title
--hy-accordion-motion-transition-expand-durationvar(--hy-motion-transition-expand-duration)Transition duration for the expand/collapse panel animation
--hy-accordion-motion-transition-expand-easingvar(--hy-motion-transition-expand-easing)Transition easing for the expand/collapse panel animation

Methods ​

toggle() ​

Toggles the accordion between expanded and collapsed states. Triggers CSS Grid animation and appropriate events.

expand() ​

Expands the accordion to show its content. Uses CSS Grid animation for smooth transition.

collapse() ​

Collapses the accordion to hide its content. Uses CSS Grid animation for smooth transition.

focus() ​

Sets focus on the accordion header button for keyboard navigation.

blur() ​

Removes focus from the accordion header button.

Built with Lit. Documented with VitePress.