ListRow

A full-width row in a list: a label, content before it and a value at the far end.

Overview

A short list where each row opens something, toggles a section or holds its own buttons.

List

Do
Bills3
import { Card, ListRow } from "@hackcove/ui";

<Card flush>
  <ListRow trailing="R 9 500">Rent</ListRow>
  <ListRow divided trailing="R 1 850">
    Transport
  </ListRow>
  <ListRow divided href="#bills" trailing="3">
    Bills
  </ListRow>
</Card>
Rows sit in a Card flush, and divided draws the line between them on every row after the first.
Don't
import { Card, ListRow } from "@hackcove/ui";

<Card>
  <ListRow trailing="R 9 500">Rent</ListRow>
  <ListRow divided trailing="R 1 850">
    Transport
  </ListRow>
</Card>
Rows in a Card that is not flush sit inside its padding, so the hover fill stops short of the edges and the lines do not run across.

Row actions

Do
Grace Hopper
import { Button, Card, ListRow } from "@hackcove/ui";

<Card flush>
  <ListRow
    static
    actions={
      <>
        <Button size="sm" variant="outline">
          Reject
        </Button>
        <Button size="sm">Accept</Button>
      </>
    }
  >
    Grace Hopper
  </ListRow>
</Card>
A row that holds its own buttons is static, and the buttons go in actions.
Don't
import { Button, Card, ListRow } from "@hackcove/ui";

<Card flush>
  <ListRow href="#grace" trailing={<Button size="sm">Accept</Button>}>
    Grace Hopper
  </ListRow>
</Card>
A button inside a link row is a control inside a control: the row opens a page and the button does something else, and a click can only mean one.

Usage

  • Put the rows in a Card flush and set divided on every row after the first. trailing is a value, a count or a Pill; leading is an Avatar or an icon.
  • A row with onClick is a button; with href (or render, for a router's link) it is a link. external opens a link in a new tab.
  • expanded makes the row the header of a collapsible section: you own the state and the section, and pass aria-controls to name it.
  • selected marks the one row whose detail is open; set it on a single row of a list.
  • A row that holds its own buttons is static: the buttons go in actions, after trailing. revealOnHover shows them only on hover or focus, so a long list is not a wall of buttons.
  • Never put a button or a link inside a button or link row. size="sm" is the dense padding for a list that must fit more rows.
  • Records with several columns to compare are a Table, not rows.

Accessibility

  • A button row is a native <button type="button">; a link row is a real link; a static row is a plain <div> with no click target.
  • selected sets aria-current="true" on the row.
  • expanded sets aria-expanded and draws a chevron, which is hidden from assistive tech.
  • A button or link row has a focus ring from the component; disabled fades the row and stops pointer events.
  • revealOnHover actions appear when the row is hovered or has focus inside it, so a keyboard user can reach them, and they are always shown on a touch screen.

API

ListRow

A full-width row that is a <button> (or, with href or render, a link) with a hover fill, a left-aligned label and trailing content at the far end. With expanded it is the header of a collapsible section: aria-expanded and a chevron. Rows sit in a Card flush; divided draws the line between them, on each row after the first. leading is content before the label, and selected marks the row in view. static makes the row a plain <div> for one that holds its own buttons (a button cannot sit inside a button or a link): actions follow trailing, and revealOnHover shows them only on hover or focus.


actions

Buttons for this row, after trailing: Button size="sm", IconButton.

Type
ReactNode

divided

A hairline above the row: set it on every row after the first.

Type
boolean

expanded

Makes the row a collapsible header: sets aria-expanded and shows a chevron that turns down when open. The caller owns the state and the section; pass aria-controls to name it.

Type
boolean

external

Opens in a new tab: adds target="_blank" and rel="noreferrer".

Type
boolean

href
Type
string

leading

Content before the label: an Avatar, a thumbnail, an icon.

Type
ReactNode

render
Type
LinkRender

revealOnHover

Hides actions until the row is hovered or something in it has focus, so a long list is not a wall of buttons. A touch screen has no hover, so they are always shown there.

Type
boolean

selected

Marks the row in view, the one whose detail is open: a violet fill and aria-current="true". Set it on one row of a list.

Type
boolean

size

sm is dense padding. Defaults to md.

Type
"sm" | "md"

static

A row that is neither a button nor a link, for one that holds its own controls: a <div> with no click target and no hover fill (unless revealOnHover), taking actions as well.

Type
true

trailing

Content at the far end of the row: a value, a count, a Pill.

Type
ReactNode