Components

Accordion

Disclosure sections with linked triggers, panels, and keyboard navigation.

When to Use

Use Accordion when a page has several related sections and readers should open only the sections they need. It works well for settings, product details, and frequently asked questions. Use Collapsible instead when there is only one independent section to show or hide.

Features

  • Supports single and multiple expanded items.
  • Supports controlled and uncontrolled state.
  • Supports horizontal and vertical arrow-key navigation.
  • Links each trigger to its content with stable ARIA IDs.
  • Supports mounted and unmounted closed content.
  • Supports RTL-aware horizontal navigation through dir and Direction.Provider.
  • Supports asChild and render on every part.

Import

import { Accordion } from "@flowstack-ui/atom";

Anatomy

<Accordion.Root>
  <Accordion.Item value="item-1">
    <Accordion.Header>
      <Accordion.Trigger />
    </Accordion.Header>
    <Accordion.Content />
  </Accordion.Item>
</Accordion.Root>

API Reference

Root

Owns the expanded-item state and keyboard-navigation settings for every item. It renders a div by default and accepts native div props.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
type"single" | "multiple""single"
valuestring | string[]-
defaultValuestring | string[]"" or [], based on type
onValueChange(value: string | string[]) => void-
collapsiblebooleantrue
disabledbooleanfalse
orientation"vertical" | "horizontal""vertical"
dir"ltr" | "rtl"Direction.Provider
Data attributeValues
[data-slot]"accordion-root"
[data-orientation]"vertical" | "horizontal"
[data-disabled]Present when the whole accordion is disabled

Item

Provides one item value and its open, closed, and disabled state to the nested Header, Trigger, and Content. It renders a div by default.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
valuestringRequired
disabledbooleanfalse
Data attributeValues
[data-slot]"accordion-item"
[data-state]"open" | "closed"
[data-disabled]Present when the item or Root is disabled

Renders the semantic heading that contains a Trigger. Choose an as level that fits the surrounding page heading structure.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
as"h1" | "h2" | "h3" | "h4" | "h5" | "h6""h3"
Data attributeValues
[data-slot]"accordion-header"

Trigger

Renders the control that toggles its Item and moves focus between sibling triggers. It renders a native button by default and supplies button semantics to custom renders.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
role"button" for non-native renders
aria-expanded"true" when open, otherwise "false"
aria-controlsID of the associated Content
aria-disabled"true" when the Item or Root is disabled
Data attributeValues
[data-slot]"accordion-trigger"
[data-state]"open" | "closed"
[data-disabled]Present when the Item or Root is disabled

Content

Renders the region controlled and labelled by its Trigger. Closed content unmounts by default; keepMounted keeps it available in the DOM and hides it after any closing animation finishes.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
keepMountedbooleanfalse
ARIA attributeValues
role"region"
aria-labelledbyID of the associated Trigger
Data attributeValues
[data-slot]"accordion-content"
[data-state]"open" | "closed"
CSS variableDescription
--content-heightMeasured content height for consumer-owned animation

Examples

Single Accordion

import { Accordion } from "@flowstack-ui/atom";

export function SingleAccordion() {
  return (
    <Accordion.Root defaultValue="shipping">
      <Accordion.Item value="shipping">
        <Accordion.Header>
          <Accordion.Trigger>Shipping</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>Orders usually ship within two days.</Accordion.Content>
      </Accordion.Item>

      <Accordion.Item value="returns">
        <Accordion.Header>
          <Accordion.Trigger>Returns</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>Unused items can be returned within 30 days.</Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
  );
}

Multiple Expanded Sections

import { Accordion } from "@flowstack-ui/atom";

export function MultipleAccordion() {
  return (
    <Accordion.Root
      type="multiple"
      defaultValue={["account", "security"]}
    >
      <Accordion.Item value="account">
        <Accordion.Header>
          <Accordion.Trigger>Account</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>Update your account details.</Accordion.Content>
      </Accordion.Item>

      <Accordion.Item value="security">
        <Accordion.Header>
          <Accordion.Trigger>Security</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>Review your security settings.</Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
  );
}

Accessibility

Accordion follows the WAI-ARIA Accordion pattern. Triggers are buttons with aria-expanded and aria-controls. Each Content is a labelled region, and each Header should use a heading level that fits the page. Keep the Trigger as the only interactive control inside its Header.

KeyDescription
Space / EnterToggles the focused Trigger.
ArrowDownMoves to the next Trigger when orientation is vertical.
ArrowUpMoves to the previous Trigger when orientation is vertical.
ArrowRightMoves next in horizontal LTR, or previous in horizontal RTL.
ArrowLeftMoves previous in horizontal LTR, or next in horizontal RTL.
HomeMoves to the first enabled Trigger.
EndMoves to the last enabled Trigger.

Changelog

See CHANGELOG.md.