List

ul.list[role="list"]

List — the structured row list: a settings list, a file list, an inbox.

Examples

Rows with a control

View “Rows with a control” as
  • Wi-Fi Connect automatically to known networks
  • Bluetooth
<ul class="list list-divided" role="list">
  <li>
    <div class="list-content">
      <span class="list-title" id="wifi-label">Wi-Fi</span>
      <span class="list-support">Connect automatically to known networks</span>
    </div>
    <div class="list-trailing">
      <input class="switch" type="checkbox" role="switch"
             aria-labelledby="wifi-label" checked />
    </div>
  </li>
  <li>
    <div class="list-content">
      <span class="list-title" id="bt-label">Bluetooth</span>
    </div>
    <div class="list-trailing">
      <input class="switch" type="checkbox" role="switch" aria-labelledby="bt-label" />
    </div>
  </li>
</ul>

When the row holds its own control, the row itself is not interactive. A button inside a link is invalid HTML and a control inside a clickable row is a target inside a target.

Rows that are links

View “Rows that are links” as

.list-action goes on the <a> and is the row: it carries the padding, the hover and the focus ring, so the whole width is the target. The <li> becomes a bare wrapper.

Tokens 29

Level 2, declared on .list itself. Set any of them on that selector to restyle this component without touching the skin.

Level 2 tokens declared by list
TokenDefault
--list-action-current-colorvar(--color-primary)
--list-action-hover-bgvar(--color-surface-sunken)
--list-action-radiusvar(--radius-field)
--list-content-gapvar(--space-1)
--list-divider-colorvar(--color-border-subtle)
--list-divider-widthvar(--border-width)
--list-lead-alignbaseline
--list-lead-gapvar(--space-1) var(--space-2)
--list-lead-size12rem
--list-leading-colorvar(--color-on-surface-muted)
--list-link-hover-bgvar(--color-surface-sunken)
--list-row-aligncenter
--list-support-colorvar(--color-on-surface-muted)
--list-support-font-sizevar(--font-size-xs)
--list-title-colorvar(--color-on-surface)
--list-title-font-sizevar(--font-size-sm)
--list-title-font-weightvar(--font-weight-medium)
--list-trailing-colorvar(--color-on-surface-muted)
--list-trailing-font-sizevar(--font-size-sm)
--list-trailing-gapvar(--space-2)
--list-row-gapvar(--space-3)
--list-row-min-size3rem
--list-row-padding-blockvar(--space-3)
--list-row-padding-inlinevar(--space-4)
--list-content-min14rem
--list-divider-insetvar(--list-row-padding-inline, var(--space-4))
--list-font-familyvar(--font-secondary)
--list-scroll-margin0
--list-spaced-gapvar(--space-2)

Variants and states

Variants

  • .list-divided
  • .list-lg
  • .list-sm

Inside it

  • .list-action
  • .list-link
  • .list-stacked
  • .list-content
  • .list-lead
  • .list-title
  • .list-trailing
  • .list-leading
  • .list-spaced
  • .list-support

State it reads

Read from the platform, never mirrored into a class that could disagree with it.

  • :disabled
  • :focus
  • :hover

Before you ship it

What you have to do 1 requirements

  1. Put role="list" on the list. The reset strips markers from any <ul> or <ol> that carries a class, and in WebKit that also drops the list semantics: VoiceOver stops announcing "list, 8 items" and reads eight unrelated lines instead. role="list" restores it. This is not optional decoration — it is the one attribute without which the component is worse than a bare <ul>. Use <ol class="list" role="list"> where the order is meaningful; the role is the same. Name a trailing control from the row. A switch or checkbox in .list-trailing has no visible label of its own — the row's title is its label. Point at it: aria-labelledby="the-title-id", or wrap the title in a <label for>. Without this the control announces as "switch" and nothing else. Nothing in CSS can supply it. An icon in .list-leading is decoration. aria-hidden="true" on the <svg>; the row's text is the name. A .list-link is named by its own text, and by nothing else. A row of twenty whose link reads "Read more" is a list of twenty things all called "Read more" — worse than .list-action, not better. Put it on the title, and put anything the reader needs and cannot see — a new tab, a file size — inside the link, sr-only if it is not to be shown. Do not put .list-link and .list-action on the same row, and do not put two of them in one row. .list-link costs the row's text its selectability. The rectangle sits over it and a drag across the row drags the link. A row whose text a reader has to copy should not be stretched. .list-lead needs list-stacked on the list, and short children. The slot only gets a line of its own when the row is allowed to wrap; and what decides whether it draws as a column or a row is whether its children fit side by side, so a child that wraps its own text has no width to decide with. Tune --list-lead-size — with --list-content-min it is the row width at which the row stacks — never a breakpoint.

src/css/components/list.css · npx mostlycss add list