Tangible Design System · @tangible/ui 0.2.29 · Interactive version · Markdown

Accordion

import { Accordion, useAccordionItem } from '@tangible/ui';

Interactive docs and examples: Accordion in Storybook.

Accordion props

Prop Type Default Description
children ReactNode
type "multiple" | "single"
className? string
collapsible? boolean Allow closing all items (otherwise one stays open)
defaultValue? string | string[] Uncontrolled: initially open item
onValueChange? ((value: string | undefined) => void) | ((value: string[]) => void) Callback when open item changes. Receives undefined when all items are closed (collapsible mode) — store it as value ?? null if your state is string | null.
value? string | string[] Controlled: currently open item value. null means "controlled, nothing open". Controlled vs uncontrolled is decided once, at mount, from whether value is undefined — so pass null (not undefined) for "all closed", and if undefined does leak back in later (onValueChange reports it on collapse), it reads as "nothing open" rather than switching modes.
variant? "card" | "flush" 'card' Visual treatment. card (default): Bordered cards with gap between items. flush: Items share borders, no gap, no radius — denser layout.

Accordion.Item

Prop Type Default Description
children ReactNode
value string Unique identifier for this item (required)
className? string
disabled? boolean false Prevent interaction
headingLevel? 2 | 3 | 4 | 5 | 6 Wrap trigger in heading element (h2–h6). Omitting this reduces discoverability for screen reader users who navigate by headings (NVDA/JAWS H key). Only omit when the accordion is already inside an appropriate heading context.

Accordion.Trigger

Prop Type Default Description
aria-label? string Accessible label for the trigger. Required when children is empty (e.g. icon-only triggers).
asChild? boolean false When true, merges trigger props (aria attributes, event handlers, keyboard navigation) onto the child element instead of rendering a built-in button. The child must be a single React element that accepts ref and event handlers. The built-in chevron indicator is not rendered in asChild mode.
children? ReactNode
className? string
unstyled? boolean false asChild only. Skip the tui-accordion__trigger class — the full-width row paint (flex, width 100%, padding, hover background, inset focus ring) — and leave the child's own styling alone. The behaviour hook (data-tui-accordion-trigger, data-state, ARIA, handlers) still lands. For a child that is already a styled control (an IconButton), not for a custom row that wants the accordion's look.

Accordion.Panel

Prop Type Default Description
children ReactNode
className? string
landmark? boolean false Render panel as a landmark region (role="region"). Default false to avoid landmark pollution with many panels.

Hooks

useAccordionItem

useAccordionItem(): AccordionItemState

Returns:

Member Type Description
value string The item's value.
isOpen boolean Whether the item is currently open.
disabled boolean Whether the item is disabled — a secondary control should disable too.
triggerId string id of the item's trigger (the built-in one, or the asChild element).
panelId string id of the item's panel — the value for a secondary control's aria-controls.
toggle () => void Toggle this item, honouring type/collapsible and disabled.

Examples

Other stories: Playground, Basic, Single (Non-Collapsible), Multiple, With Step Indicators, Course Syllabus, Controlled, Disabled Items, Keyboard Navigation, Flush Variant, Without Headings (interactive page).

Component API tokens

Read via fallback, never declared. Set one on an ancestor to restyle every instance under it.