videorc/ui

List Row

The one row for every icon, title and meta list, and the inset grouped list it sits in. 32 px rows split by hairlines, facts unless they say otherwise, with a whole-row button or a stretched title button when a row acts.

Cameras
FaceTime HD CameraBuilt-inIn use
Sony ZV-E10USBConnected
Microphones
Shure MV7USBIn use
AirPods ProBluetoothNot responding

Installation

$ pnpm dlx shadcn@latest add @videorc/list-row

Usage

import { GroupedList, ListRow, ListRowButton } from "@/components/list-row";
<GroupedList label="Cameras">
  <ListRow
    context="Built-in"
    icon={<CameraIcon />}
    meta="In use"
    title="FaceTime HD Camera"
  />
</GroupedList>

Use it for sets of like things: sources, devices, destinations, scenes, settings. Lists, not card stacks: a card is only for an object with a picture, such as a scene thumbnail or a background.

Don't hand-roll an icon, title and meta row, and don't put cards inside a grouped list. A fact row that jumps to the page owning its value is a Navigable Row.

Anatomy

<GroupedList label>
  <ListRow leading icon title context alias statusIcons meta>
    {/* trailing controls */}
  </ListRow>
</GroupedList>

Examples

A row with its own controls

A row that holds a control, such as a switch, stays a div. Put a ListRowButton in its title and give the row relative: the button stretches over the whole row, so a click anywhere on it acts, while the switch stays its sibling instead of nesting inside a button. interactive adds the hover.

Destinations
Maya Streams
maya_streams

The whole row as a button

as="button" makes the row one button, with the hover and the focus ring. selected draws the accent block; pair it with aria-pressed or aria-current. compact is 28 px.

Scenes

Theming

Token or attributeMeaning
h-row, h-row-compact32 px, or 28 px when compact
rounded-row8 px on a row alone; none inside a GroupedList, which owns the radius
bg-inset, divide-borderThe grouped list's inset fill and its hairlines
bg-accentThe hover of an interactive row, and the selected row
text-metaThe 12 px meta label
data-selectedOn a selected row
data-slot="platform-mark"On a platform mark in the icon tile: it's never clipped to the chip radius
data-slotlist-row, list-row-icon, list-row-title, list-row-context, list-row-meta, grouped-list, list-row-button

Keyboard

KeyAction
TabMoves to a row that's a button or holds a ListRowButton, then to the row's own controls
Enter, SpaceActivates it

Accessibility

A fact row is plain text. A row that's a button is named by its content, the title, context and meta in order, so keep the meta short. Selection is a block of colour: say it with aria-pressed or aria-current too. A trailing control needs its own name ("Stream to YouTube").

GroupedList passes its attributes to the list itself, so aria-label names the group for assistive tech.

API reference

ListRow

Every div attribute, or every button attribute with as="button", plus:

Prop

Type

GroupedList

Every div attribute, on the list itself, plus:

Prop

Type

ListRowButton

Every button attribute. Give its ListRow relative, and position any control in the row that must stay clickable (Switch already is).