Skip to content
Protocore Design Systemv1.6.9

/// Data Display

ListCell

Composable list row: leading slot, title/subtitle, trailing controls, optional selection and whole-row link.

import { ListCell } from "@protocore/pds";
View as Markdown

Basics

A leading slot (avatar / icon / thumbnail), a title + optional subtitle, and a trailing slot for controls or meta. Rows share a hairline divider and stack straight into a list.

ALAda Lovelaceada@protocore.ioOwner
ATAlan Turingalan@protocore.ioMember
GHGrace Hoppergrace@protocore.ioMember

Selectable

Set selectable to add a leading Checkbox. It's controllable via selected / defaultSelected / onSelectedChange, and a selected row tints with the accent-muted wash.

ALAda Lovelaceada@protocore.io
ATAlan Turingalan@protocore.io
GHGrace Hoppergrace@protocore.io

When to use it

ListCell is the general-purpose row for settings lists, member directories, file browsers, and pickers — anywhere each item pairs an identity with controls or navigation. It composes with Persona, Avatar, Badge, and IconButton in its slots.

When the row is a flat, mono, column-aligned record (careers, changelogs, endpoint directories), use ListingRow. When you need sorting, a header, or pagination, graduate to DataTable.

Usage

Do

  • Use `href` for navigating rows — it stretches one anchor over the surface.
  • Keep trailing controls to a small, consistent set across the list.
  • Pair `selectable` with a controlled `selected` for bulk-selection UIs.
  • Compose a Persona into `leading`+`title`, or use the slots directly.

Don't

  • Don't add a second link inside a row that already has an `href`.
  • Don't attach an onClick to fake a link — use `href` for whole-row navigation.
  • Don't overload the `trailing` slot; two controls is plenty.
  • Don't rely on the selected tint alone — the Checkbox carries the state.

Accessibility

KeysAction
TabMoves focus to the row link (when href) and to the Checkbox / trailing controls.
EnterFollows the row link (native anchor).
SpaceToggles the selection Checkbox when focused.
  • The whole-row link is a single stretched anchor named by the `title` — no nested clickables.
  • The selection Checkbox is labelled by `selectLabel` (default "Select item").
  • Trailing controls and the Checkbox sit above the stretched link so they remain independently operable.
  • ListCell imposes no list role — provide `role="listitem"` / `role="option"` from the parent context.

ListCell props

PropTypeDefaultDescription
classNamestring
defaultSelectedbooleanfalseUncontrolled initial selected state.
hrefstringWhen set, the whole row becomes a single link: a stretched anchor covers the surface (keyboard- and screen-reader-correct), while `trailing`/Checkbox stay clickable above it. Without it the row renders no pointer or hover affordance.
leadingReactNodeLeading slot — an Avatar, Icon, thumbnail, or any mark.
onSelectedChange((selected: boolean) => void)Fires when the selection Checkbox toggles.
selectablebooleanfalseShow a leading selection Checkbox.
selectedbooleanControlled selected state (pairs with `onSelectedChange`).
selectLabelstringSelect itemAccessible label for the selection Checkbox.
sizeenummdRow density.
styleCSSProperties
subtitleReactNodeOptional muted second line.
title *ReactNodePrimary line, rendered in ink. When `href` is set this becomes the row link.
trailingReactNodeTrailing slot — a control, badge, menu trigger, or meta. Stays clickable above the row link.

Related

  • PersonaUser identity row: avatar + name + optional secondary line, presence dot, and trailing action.
  • AvatarGroupOverlapping stack of square avatars with a muted +N overflow chip; capped by max.
  • ListingRowA scannable list row — mono title, mono meta columns, and a trailing outbound arrow; hover dims to 0.6.
  • CheckboxBoxy 16px checkbox with checked, unchecked, and indeterminate states and an optional label.