Skip to main content

List

MD3 (Expressive) list: a vertical <ul> of one-, two- and three-line items with leading and trailing slots, clickable rows with separately focusable trailing controls, single / multiple selection, and a segmented variant.

Lines​

Items size themselves to one line (56dp), two lines (72dp) or three lines (88dp) from the presence of overline / supportingText; supporting text that wraps also makes the item three-line.

  • One-line item
  • Two-line itemSupporting text
  • OverlineThree-line itemSupporting text that is long enough to wrap onto a second line
<List>
<ListItem headline="One-line item" />
<ListItem headline="Two-line item" supportingText="Supporting text" />
<ListItem overline="Overline" headline="Three-line item" supportingText="…" />
</List>

Leading and trailing content​

leading takes an icon, avatar, image or video; trailing an icon or control; trailingSupportingText a right-aligned label. Give decorative icons aria-hidden and images an alt.

  • StarredLeading icon, trailing icon
  • LakesideLeading image100+
  • DesertLeading image12
<ListItem
leading={<StarIcon aria-hidden />}
headline="Starred"
supportingText="Leading icon, trailing icon"
trailing={<ChevronRightIcon aria-hidden />}
/>

Clickable rows​

onClick makes a row actionable: its leading slot and text become one native <button> covering the row (ripple, focus ring). href renders an <a> instead. selected applies the secondary-container fill and disabled dims the row to 38%.

<ListItem headline="Inbox" onClick={() => openFolder('inbox')} />
<ListItem headline="Documentation" href="/docs" />

Rows with trailing controls​

On a clickable row, trailing is rendered beside the primary action, not inside it, so a Switch or icon button there stays its own control. A static row can hold a control in its leading slot, such as a Checkbox.

  • Share usage dataStatic row with a leading checkbox
<ListItem
headline="Wi-Fi"
onClick={openWifiSettings}
trailing={<Switch aria-label="Wi-Fi" selected={wifi} onChange={(e, v) => setWifi(v)} />}
/>

Selection​

Set selectionMode="single" or "multiple" and give each ListItem a value; the list owns the state through value / defaultValue / onChange(event, value). Selection should not rely on color alone — add a check or radio indicator.

  • Wi-Fi
  • Ethernet
  • Cellular
  • Bluetooth
  • NFC
  • Location
  • Ultra-widebandUnavailable
const [value, setValue] = useState<string | null>('wifi')

<List
selectionMode="single"
value={value}
onChange={(event, next) => setValue(next)}
aria-label="Preferred network"
>
<ListItem value="wifi" headline="Wi-Fi" />
<ListItem value="ethernet" headline="Ethernet" />
</List>

Segmented​

variant="segmented" renders each item as its own surface-colored segment, 2dp apart, with 16dp outer corners on the first and last item. It works with clickable rows and selection lists alike.

  • Option A
  • Option B
  • Option C
<List variant="segmented">
<ListItem headline="First" onClick={…} />
<ListItem headline="Second" onClick={…} />
</List>

Accessibility​

  • The focusable rows share one Tab stop (the selected row, else the first, then the last focused one). Down / Right and Up / Left move between rows, wrapping at the ends (mirrored in RTL); Home / End jump to the ends.
  • Controls in a row's trailing slot — and in the leading slot of a static row — stay Tab stops and are part of the arrow sequence; controls that use arrow keys themselves (text inputs, sliders, radios) keep them.
  • A clickable row's primary action is a native <button> / <a>: role, tabIndex, onKeyDown and aria-* props land on that element.
  • With a selectionMode, the list is a listbox (label it with aria-label) and its items are options with aria-selected; Enter / Space or a click selects. Options cannot hold interactive controls.

Props​

List​

PropTypeDefaultDescription
defaultValuestring | number | readonly string[] | string[] | nullnull []Unused without a selection model (kept for HTMLAttributes compatibility). Uncontrolled initial selected item value. Uncontrolled initial selected item values.
onChangeChangeEventHandler<HTMLUListElement, Element> | ((event: SyntheticEvent<Element, Event>, value: string | null) => void) | ((event: SyntheticEvent<...>, value: string[]) => void)—Native `change` events bubbling from descendants. Fires with the triggering event and the next selected value. Fires with the triggering event and the next selected values.
selectionModeenum'none'
valuestring | string[] | null—Controlled selected item value (`null` = none). Controlled selected item values.
variantenum'standard'`standard`: items on a transparent container. `segmented`: each item is its own surface-colored segment, 2dp apart, with 16dp outer corners on the first and last item (Compose `SegmentedListItem`). Both use the Expressive item shapes.

ListItem​

PropTypeDefaultDescription
disabledbooleanfalseDisable the item and dim its content to 38%.
headline *ReactNode—Primary text (headline).
hrefstring—Make the row a link: the primary action becomes an `<a href>`.
leadingReactNode—Leading element (icon, avatar, image, video; or a checkbox / radio / switch on a static row). Not hidden from assistive technology — give decorative icons `aria-hidden` and images an `alt`. On an actionable row it is part of the primary action, so do not put controls here.
onClickMouseEventHandler<HTMLElement>—Click handler. Providing it makes the row actionable: the leading slot and the text become one `<button>` (the primary action).
onKeyDownKeyboardEventHandler<HTMLElement>—Key handler of the focusable element — the primary action of an actionable row, else the root. Runs before the row's own activation: `event.preventDefault()` suppresses it.
overlineReactNode—Small label above the headline.
relstring—`<a rel>` — only with `href`.
selectedbooleanfalseMarks the item selected (secondary-container fill). Inside a `List` with a `selectionMode`, the list's `value` decides instead.
supportingTextReactNode—Secondary text below the headline.
targetstring—`<a target>` — only with `href`.
trailingReactNode—Trailing element (icon, metadata, or controls such as a Switch / icon button). On an actionable row it is rendered **beside** the primary action, not inside it, so its controls stay separately focusable (multi-action list). Non-interactive trailing content lets clicks through to the row.
trailingSupportingTextReactNode—Trailing metadata text (right-aligned label).
valuestring—The item's value in a `List` with a `selectionMode` (B17): the item then renders `role="option"` with `aria-selected`.