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,onKeyDownandaria-*props land on that element. - With a
selectionMode, the list is alistbox(label it witharia-label) and its items areoptions witharia-selected; Enter / Space or a click selects. Options cannot hold interactive controls.
Props
List
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | number | readonly string[] | string[] | null | null
[] | Unused without a selection model (kept for HTMLAttributes compatibility). Uncontrolled initial selected item value. Uncontrolled initial selected item values. |
onChange | ChangeEventHandler<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. |
selectionMode | enum | 'none' | |
value | string | string[] | null | — | Controlled selected item value (`null` = none). Controlled selected item values. |
variant | enum | '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
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | false | Disable the item and dim its content to 38%. |
headline * | ReactNode | — | Primary text (headline). |
href | string | — | Make the row a link: the primary action becomes an `<a href>`. |
leading | ReactNode | — | 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. |
onClick | MouseEventHandler<HTMLElement> | — | Click handler. Providing it makes the row actionable: the leading slot and the text become one `<button>` (the primary action). |
onKeyDown | KeyboardEventHandler<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. |
overline | ReactNode | — | Small label above the headline. |
rel | string | — | `<a rel>` — only with `href`. |
selected | boolean | false | Marks the item selected (secondary-container fill). Inside a `List` with a `selectionMode`, the list's `value` decides instead. |
supportingText | ReactNode | — | Secondary text below the headline. |
target | string | — | `<a target>` — only with `href`. |
trailing | ReactNode | — | 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. |
trailingSupportingText | ReactNode | — | Trailing metadata text (right-aligned label). |
value | string | — | The item's value in a `List` with a `selectionMode` (B17): the item then renders `role="option"` with `aria-selected`. |