Skip to content
Cynosurev0.5.0
SearchStorybookGitHubnpmColour mode: System. Switch to Light

Components / More

ListRow

Interactive rows for an app's lists (notifications, an activity feed, saved queries, query history, connections): a leading slot, a title with up to two quieter lines, a trailing slot, and actions shown on hover or focus. ListRows is the list that holds them and gives it one Tab stop and arrow keys.

Default

When to useLink to "When to use"

  • A list of things to open: each row is a button (onClick) or a link (href), with the open one marked active.
  • Rows with their own commands: run, delete, a Menu of more, beside the row rather than inside it.
  • Feeds that carry state: unread, dimmed (seen), and a tone rail for an error or a warning.

Use something else when:

UsageLink to "Usage"

tsx
Copy
import { IconButton, IconTile, ListRow, ListRows } from "@arshad-shah/cynosure";
import { alert, play, trash } from "@arshad-shah/cynosure/icons";

<ListRows label="Notifications" divided>
  {notifications.map((n) => (
    <ListRow
      key={n.id}
      label={n.message}
      description={n.source}
      trailing={n.time}
      leading={<IconTile icon={alert} size="sm" tone="danger" />}
      tone={n.level === "error" ? "danger" : undefined}
      unread={!n.read}
      dimmed={n.read}
      active={n.id === openId}
      onClick={() => open(n.id)}
      actions={
        <>
          <IconButton icon={play} label="Open" size="sm" variant="ghost" onClick={() => open(n.id)} />
          <IconButton icon={trash} label="Dismiss" size="sm" variant="ghost" onClick={() => dismiss(n.id)} />
        </>
      }
    />
  ))}
</ListRows>;

StatesLink to "States"

active draws an accent rail on the inline start and tints the row, and sets aria-current (page on a link row). unread makes the title bold and adds an accent dot. dimmed mutes the title and turns the leading slot grey; nothing is faded, so text in it (an avatar's initials) stays readable. tone draws a rail and a faint wash in that colour. The words "Unread" and the tone's name ("Error", "Warning", "Success", "Info") are read with the title; replace them through labels on ListRows, or set one to "" to read nothing.

Active unread dimmed and tones

Meta linesLink to "Meta lines"

description and detail sit under the title, smaller and muted; mono sets one of them in the monospace font (a connection string, a query). Every line is cut with an ellipsis; wrap lets the title wrap instead.

Meta lines and wrapping

With href the row is a link (through LinkBase: unsafe schemes such as javascript: are not linked).

Rows as links

PropsLink to "Props"

Every prop of ListRow
PropWhat it doesTypeDefault
labelRequired
The row's title, on one line (cut with an ellipsis unless wrap). Names the row's button or link.ReactNode
description
A first, quieter line under the title.ReactNode
detail
A second quieter line, under the description.ReactNode
mono
Draws the description or the detail in the monospace font (a connection string, a query)."description" | "detail"
leading
Before the text: an IconTile, an Avatar, an Icon or a Badge status dot.ReactNode
trailing
After the text: a time, a count, a Badge. Plain content, never a control (put controls in actions).ReactNode
actions
Controls for this row (IconButtons, a Menu), drawn over the trailing slot while the row is hovered or has focus, and always shown where there is no hover (touch). Tab from the row, or Right, reaches them.ReactNode
active
The open or selected entry: an accent rail on the inline start and a tinted background; aria-current.boolean
unread
Not read yet: a bold title and an accent dot, and "Unread" after the title for assistive technology.boolean
dimmed
Seen or inactive: a muted title and a grey leading slot.boolean
tone
A coloured rail and a faint wash (an error or warning entry); the tone's word is read before the title.Tone
wrap
Lets the title wrap onto more lines instead of cutting it. Default false.booleanfalse
onClick
Makes the row a button.MouseEventHandler<HTMLElement>
href
Makes the row a link (rendered through LinkBase, so unsafe schemes are not linked). Wins over a button.string
className
Added to the row (li), for layout.string
style
Layout only. Restyle through --cy-list-row-* tokens.CSSProperties

Generated from the type definitions in @arshad-shah/cynosure 0.5.0.

Behaviour and accessibilityLink to "Behaviour and accessibility"

The pattern is a list of buttons or links with a roving Tab stop, not a listbox: a listbox's options cannot hold the row's actions (ARIA allows no controls inside an option), and these rows open things rather than choose a value. The selected entry is marked with aria-current.

Behaviour and accessibility, table 1
KeyDoes
TabInto the list on the active row (else the first, or the one used last); from a row, to its actions; then out
Down / UpThe next or previous clickable row (no wrap); rows that cannot be pressed are skipped
Home / EndThe first or last clickable row
Right / Left (mirrored RTL)From the row into its actions and along them, and back
Enter, SpacePresses a button row (Enter follows a link row)
  • Only the title is inside the row's button or link; its hit area covers the whole row, so a press on the leading slot, the text or the trailing slot lands on it. The button is named by the title (with the tone's word and "Unread") and described by the leading slot, the meta lines and the trailing slot.
  • Actions are siblings of that button. The actions of the row holding the Tab stop are in the Tab order; other rows' actions are reached with Right. A row without onClick or href keeps its actions in the Tab order.
  • Arrow keys inside a menu opened from the actions belong to the menu, and the actions stay shown while it is open.

TouchLink to "Touch"

Where the device has no hover, the actions are always shown, in their own place at the end of the row instead of over the trailing slot. Rows are at least 44px tall on a coarse pointer (24px otherwise), and IconButtons keep their own 44px hit areas.

ThemingLink to "Theming"

Tokens: --cy-list-row-background (set it to the colour of the surface the list sits on, so the actions cover the trailing slot cleanly), --cy-list-row-gap, --cy-list-row-padding-inline, --cy-list-row-rail-width, --cy-list-row-hover-mix, --cy-list-row-active-mix, --cy-list-row-wash-mix, --cy-list-row-meta-color, --cy-list-row-dimmed-filter, --cy-list-row-divider-color.

These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.

Getting started
Theming
Icons
Accessibility
Code editors and highlighters
Using Cynosure without React
Build-tool adapters
Components
Accordion
AppShell
AspectRatio
Breadcrumbs
Calendar
Card
Container
Disclosure
Divider
DocumentViewport
Grid
Inline
PageHeader
PanZoomCanvas
ScrollArea
SideNav
SortableList
SplitPane
Stack
StatusBar
Tabs
TitleBar
Toolbar
Tree
VirtualList
ZoomControls
Announcer
Avatar
Badge
CodeBlock
DescriptionList
EmptyState
ErrorBoundary
Field
Heading
IconTile
Image
Kbd
List
LoadingDots
Notice
ProgressBar
Prose
Skeleton
Stat
Steps
Table
Text
Button
Checkbox
Checklist
ColorField
ColorSwatches
Combobox
CompareSlider
CopyButton
DateField
FileDrop
IconButton
KeyValueEditor
Link
NumberField
Pagination
PathField
RadioGroup
SearchField
SegmentedControl
Select
SelectionFrame
SignaturePad
Slider
Switch
TagInput
TextArea
TextField
ThemeToggle
TimeField
ButtonBase
ChoiceBase
DialogBase
FileInputBase
HiddenValue
Icon
InputBase
LinkBase
LiveRegion
TextAreaBase
ChatMessage
Choice
DataGrid
DeviceFrame
HighlightedText
HotkeyField
ListRow
OptionList
OverlayFrame
QRCode
RowActions
Section
SiteFooter
SiteHeader
SkipLink
SortButton
VisuallyHidden
CommandPalette
ContextMenu
Dialog
FloatingToolbar
HoverCard
Menu
Menubar
Popover
ProgressOverlay
Sheet
Toast
Tooltip
Changelog