Knit UI
GitHub

Usage

Compose Accordion.Item with an Accordion.Control and an Accordion.Panel. The item's value is its identity — that is what value / defaultValue refer to.

import { Accordion } from "@knitui/components";

<Accordion defaultValue="shipping">
  <Accordion.Item value="shipping">
    <Accordion.Control>Shipping</Accordion.Control>
    <Accordion.Panel>Ships in 2–3 days.</Accordion.Panel>
  </Accordion.Item>

  <Accordion.Item value="returns">
    <Accordion.Control>Returns</Accordion.Control>
    <Accordion.Panel>30 days, no questions.</Accordion.Panel>
  </Accordion.Item>
</Accordion>;

multiple lets several sections be open at once — and changes the shape of value from a string to an array, which TypeScript enforces for you.

chevronPosition="left" moves the indicator, chevron replaces it, and disableChevronRotation keeps it still if your own glyph shouldn't spin.

Panels stay mounted by default (keepMounted), so form state inside a closed section survives. Set keepMounted={false} when a panel is expensive.

When to use something else

  • Views that replace each other rather than stacking → Tabs
  • A single show-more/show-less region → Collapse or Spoiler

Examples

Variants

Each container variant.

Loading example…

VariantsSourceStorybook

Shadows

Elevation via the shared shadow ladder — inherited from Box, so every component accepts it; no shadow unless set.

Loading example…

ShadowsSourceStorybook

Multiple

Multiple panels open at once.

Loading example…

MultipleSourceStorybook

Chevron Left

Chevron pinned to the left of the label.

Loading example…

Chevron LeftSourceStorybook

Custom Chevron

A custom chevron glyph replaces the default.

Loading example…

Custom ChevronSourceStorybook

With Icons

An icon to the left of each label.

Loading example…

With IconsSourceStorybook

Disabled Control

A disabled control cannot be toggled.

Loading example…

Disabled ControlSourceStorybook

Heading Order

order promotes each control to a real heading level for screen readers.

Loading example…

Heading OrderSourceStorybook

Controlled

Controlled — the open item is owned by the parent.

Loading example…

ControlledSourceStorybook

Sizes

Representative size keys — controls scale the header height and label font.

Loading example…

SizesSourceStorybook

Styles

Per-slot styles targets individual parts — here the control, label, and panel.

Loading example…

StylesSourceStorybook

Props

PropTypeDefaultDescription
chevronReactNode—Custom chevron icon.
chevronIconSizestring | number | undefined—Size of the default chevron glyph; ignored when a custom `chevron` is set. When unset the glyph keeps the kit's default size (14px) — a deliberate divergence from Mantine's 16 so a plain `<Accordion>` is pixel-identical.
chevronPositionAccordionChevronPosition | undefined
left · right
'right'Position of the chevron.
chevronSizestring | number | undefined'auto'Size of the chevron container — gives every chevron a fixed centered slot.
childrenReactNode—`Accordion.Item` children.
defaultValueAccordionValue<Multiple> | undefined—Uncontrolled initial value.
disableChevronRotationboolean | undefinedfalseDisable the default chevron rotation animation.
disabled systemboolean | undefined——
keepMountedboolean | undefinedtrueKeep inactive panels mounted (hidden).
multipleMultiple | undefinedfalseAllow multiple items open simultaneously.
onChange((value: AccordionValue<Multiple>) => void) | undefined—Called when value changes.
orderAccordionHeadingOrder | undefinedundefinedHeading level at which `Accordion.Control` is announced — renders the control inside `role="heading"` + `aria-level={order}`. When unset, the control has no heading semantics (a plain pressable).
radius systemstring | number | undefined'md'Corner rounding.
shadow system"xs" | "sm" | "md" | "lg" | "xl" | "xxs" | "xxl" | undefined——
size system"xs" | "sm" | "md" | "lg" | "xl" | "xxs" | "xxl" | undefined'md'Control size — scales the header `paddingHorizontal`/`minHeight`, the label font, and the default chevron glyph off the shared `controlMetrics` row.
styles systemSlotStyles<AccordionStyles> | undefined—Uniform per-slot style passthrough — sugar over the composable parts. Slots: `root` / `item` / `control` / `label` / `chevron` / `panel`. Distributed through context so it reaches every nested part. Explicit inline props on a composed part always win.
theme systemThemeName | null | undefined—Applies a theme to this element
transitionDurationnumber | undefined200Panel expand/collapse transition duration in ms.
transitionTimingFunctionstring | undefined'ease'Panel expand/collapse transition timing function.
valueAccordionValue<Multiple> | undefined—Controlled value.
variant systemAccordionVariant | undefined
default · contained · filled · separated
'default'Visual style.

Style slots

Every part of Accordion can be styled through the styles prop. Explicit props on the component always win over slot styles.

SlotTargets
chevronProps for the chevron container wrapping the glyph (.Chevron).
controlProps for each Accordion.Control header (.Control).
itemProps for each Accordion.Item (.Item) — its stylable frame surface. variant is context-driven; value/children are the part's own (identity + content), so the sugar targets the frame like the sibling slots do.
labelProps for the label text inside each control (.Label).
panelProps for each Accordion.Panel (.Panel).
rootProps for the Accordion root (.Root).

Plus 496 inherited style props from Box — the full Tamagui/React Native style surface, including token shorthands like p, mx, bg and c. See Tokens for the scales they accept, or the full list.

Accessibility

Each control is a role="button" with aria-expanded reflecting its state, and each panel is a role="region", which is the ARIA disclosure pattern.

Controls are made focusable and operable through the shared useKeyboardActions hook, since the control frame is a styled Box rather than a native <button>.

KeyAction
TabMove to the next accordion control
Space / EnterToggle the focused section

Set order when the accordion is part of the page's document outline. It wraps each control in role="heading" with a matching aria-level, which is what lets screen-reader users jump between sections with heading navigation instead of tabbing through every control. Without it the controls are buttons with no heading semantics — fine for a compact widget, a real loss for an FAQ page. Pick the level that fits the surrounding headings:

<Accordion order={3}>{/* controls become level-3 headings */}</Accordion>

Arrow keys deliberately do not move between controls: ARIA lists that as optional for accordions, and Tab already reaches every control in order.

Edit this page on GitHub