MD3 React

List

Rows of one to three lines with leading and trailing slots, static or clickable.
import { List, ListItem } from "@brijbyte/md3-react/list";
@import "@brijbyte/md3-react/ripple.css";
@import "@brijbyte/md3-react/list.css";

Anatomy

List is a <ul role="list">; each ListItem is a row with a headline (its children) plus optional overline, supportingText, leading, trailing, and trailingSupportingText slots. The row's height follows the line count — 56, 72, or 88dp for one, two, or three lines — derived automatically from which text slots are present. Because CSS can't measure whether supporting text wraps, pass lines={3} when it does, so the row switches to the three-line height and top-aligns its content like the spec requires.

Leading icons render at 24dp in on-surface-variant; avatars, images, and thumbnails size themselves. Separate rows or groups with a Divider.

  • Documents24
  • PhotosEdited 2 days ago
  • SHAREDTeam driveLong-press an item to change who can see it and edit it.

Interactive rows

Pass onClick or href (or set interactive) to make a row respond to pointer, keyboard, and focus: it renders as a <button> or <a> inside its <li>, gains the MD3 state layer and ripple, and shows the focus ring. For client-side routing, pass your router's link component via the as prop — <ListItem as={Link} to="/inbox"> — and the row renders it (still wrapped in its <li>), implying interactive; props follow the component, so to is type-checked. selected tints the row with the secondary-container color for single-select lists (settings panes, navigation), and disabled dims it to 38% and drops the interactions.

  • SecurityManaged by your organization

Selection controls

Put a Checkbox, Switch, or Radio in the leading or trailing slot to make rows selectable — checkboxes for multi-select, switches for settings, radios for a single choice. Set as="label" so a click anywhere on the row activates that control: the row becomes a <label> and the control stays the one focusable, keyboard-operable element — no nested buttons, no extra JS.

Switches — toggle a setting
Checkboxes — select multiple
Radio buttons — select one

Gaps & dividers

Separate rows two ways. A contained list (a filled, rounded surface like the ones above) leans on gaps and shape for grouping. An uncontained list — sitting directly on the background — uses a Divider between rows when a stronger separation is needed. This inbox pairs leading avatars (40dp, title-medium) with a trailing timestamp.

  • AKAnita KumarReady for another review pass?9:41
  • TWTheo WuShipped the token rename 🎉8:12
  • MRMaya RaoCan you take the on-call swap?Yesterday
  • #Devs channelPriya: the flaky test is fixedMon

Accessibility

The container carries role="list" and each item is a list item, so assistive tech announces the count and position. Interactive rows are real buttons or links — reachable by Tab, activatable with Enter/Space, and never keyboard traps. A selected row adds aria-current; for a true single-select listbox, add role="listbox"/role="option" and manage aria-selected yourself, since a plain list doesn't imply that semantic.