Expandable List

PreviousNext

A list where each item reveals an inline Elevated panel on click — nesting the Surface system in-page instead of in an overlay. Multiple items can stay open at once.

  • You're billed monthly based on active seats. Adding or removing a teammate prorates the next invoice automatically — no manual adjustment needed.

Installation

pnpm dlx shadcn@latest add https://matos-ui.com/r/expandable-list.json

Usage

import {
  ExpandableList,
  ExpandableListItem
} from '@/components/matos-ui/expandable-list'
<ExpandableList defaultOpenValues={['billing']}>
  <ExpandableListItem value="billing" title="How does billing work?">
    You're billed monthly based on active seats.
  </ExpandableListItem>
  <ExpandableListItem value="export" title="Can I export my data?">
    Yes — every workspace can export a full JSON snapshot.
  </ExpandableListItem>
</ExpandableList>

How it's built

  • Each closed row is a flat trigger — no Elevated of its own. The panel revealed on expand is Elevated offset={1} relative to the list, so it reads a step above it — the same outer/inner relationship the Elevated primitive uses everywhere else, just nested inline instead of in a portal.
  • Expand/collapse uses spring.moderate — the tier the Motion Tokens reserve for panels that need to settle precisely.
  • The height change is never animated directly (height: "auto" never tweens cleanly). Instead the item wrapper has Framer Motion's layout prop, and only the panel's opacity/position animate — Framer measures the before/after box and turns that into a smooth resize on its own.
  • Multiple items can be open at the same time by default — this is deliberately not an accordion. Reach for Accordion when only one panel should ever be open.
  • prefers-reduced-motion drops the layout animation and the panel's spatial offset; only the opacity fade remains.

Reference

ExpandableList Props

PropTypeDefaultDescription
childrenReactNodeExpandableListItem children.
defaultOpenValuesstring[][]Item values expanded on mount.

ExpandableListItem Props

PropTypeDefaultDescription
valuestringUnique identifier for the item.
titleReactNodeTrigger row content.
childrenReactNodeContent revealed inside the Elevated panel.

Interactions

  • Click a row (or press Enter/Space while it's focused) to toggle it open or closed.
  • Arrow Up / Arrow Down moves focus between triggers, regardless of which items are currently open.
  • Each trigger sets aria-expanded and aria-controls; the revealed panel is a labelled role="region".