ListItem
Presentational row for menus, selects, palettes, and lists: leading icon, truncating label, end-aligned meta (text, Badge, Kbd, StatusDot, value), trailing icon, selection check, and a destructive tone. Consumers own semantics.
Status: stable. Group: display. Markdown version: /design-system/components/list-item.md
When to use
ListItem renders the visual anatomy of a menu, select, palette, or list row: a leading icon, a truncating label, end-aligned meta content, a trailing icon, and a selection check. It is purely presentational; the interactive wrapper (a Radix Item, a native li/option, or a button) owns role, focus, and events. meta stays exposed to assistive tech since it often carries information (a shortcut, a status, a value); icon, trailingIcon, and the selected check are decorative.
When not to use
- Do not add role, tabIndex, or onClick to ListItem; the interactive wrapper (Radix Item, li, option, button) owns keyboard, focus, and events.
- Do not rely on selected/highlighted for semantics; they are visual only; pair them with real ARIA (aria-selected, aria-checked, data-highlighted) on the wrapper.
- Do not use disabled as the only signal for a non-interactive row; pair it with aria-disabled on the wrapper so assistive tech announces the state.
Look-alikes
The contract names no look-alike with a deciding condition.
Props
| Prop | Type | Default | Description | Required |
|---|---|---|---|---|
children | React.ReactNode | none | Primary label. Truncates with an ellipsis; never wraps. | Yes |
icon | React.ReactNode | none | Leading icon node; rendered in a fixed gutter so labels column-align. | No |
meta | React.ReactNode | none | End-aligned secondary content: muted small text, Badge, Kbd, StatusDot, or a value. Exposed to AT. | No |
trailingIcon | React.ReactNode | none | Trailing icon after meta, always aria-hidden: use it for decorative glyphs such as a chevron. A glyph that carries meaning (an external-link arrow) is hidden from screen readers here, so say it in the label or meta too. | No |
selected | boolean | false | Renders the check indicator in the trailing position. Visual only; semantic selection belongs to the consumer. | No |
tone | "neutral" | "destructive" | neutral | Destructive rows (deletions) use the error color treatment. | No |
disabled | boolean | false | Visual disabled treatment via the canonical disabled tokens. The consumer carries aria-disabled. | No |
highlighted | boolean | false | Parent-driven active row (combobox/palette). Radix menus work without it via [data-highlighted]. | No |
className | string | none | No description in the contract. | No |
Variants
- Available tones:
neutral,destructive(defaultneutral).
Invalid combinations
The contract records no invalid combinations.
Keyboard
The contract records no keyboard interaction.
Rules
Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.
| Level | Rule | How it is checked |
|---|---|---|
| MUST | ARIA: No own ARIA; the interactive wrapper (Radix Item, button, li, option) owns role, aria-selected/aria-checked, and aria-disabled. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Meta is exposed to assistive tech (no aria-hidden); icon, trailingIcon, and the selected check are decorative (aria-hidden). | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | Required stories produce no axe violations at the configured severity. | Automated by npm run test:stories:matrix:ci. WCAG 2.5.8. |
| MUST | The accessibility tree (role, name, state) matches the committed snapshot for every required story. | Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2. |
| MUST | The component remains legible and operable under a real browser forced-colors: active pass. | Automated by npm run test:stories:hc. |
| MUST | A human completed an end-to-end accessibility review of this component. | Manual review, last on 2026-11-04. |
| SHOULD | Wrap ListItem in the element that owns interaction; Radix MenuItem/Item, a native li/option, or a button; and let that element carry role, tabIndex, and event handlers. | Not stated in the contract. |
| SHOULD | Use meta for content the user needs to hear or read (a Kbd shortcut, a StatusDot, a value); use trailingIcon only for purely decorative glyphs like a chevron. | Not stated in the contract. |
| SHOULD | Set tone="destructive" for irreversible actions (delete, remove) so the row picks up the error color treatment. | Not stated in the contract. |
Install and import
- Install:
npm install @digitaltableteur/react(version 0.9.1, restricted access on npm). - Import:
import { ListItem } from "@digitaltableteur/react"; - Entry point:
@digitaltableteur/react/contentexports it too. - Styles: import
@digitaltableteur/react/style.cssonce at the app boundary. - Also available as the custom element
<dt-list-item>; see the custom elements manifest.
Links
- Machine-readable contract (Design System Contract 1.0)
- Markdown version of this page
- Component index as JSON
- All components
- Source: The implementation lives in a private repository. This page, its Markdown twin and the contract are generated from it at build time and are the public source of truth.