Table

Lists records that share the same fields.

Sizes

  • JobTableRows
    job_4f2a91events_daily1,204,330
    job_4f2a90orders88,412
    job_4f2a8esessions402,118

    defaultdefault

  • JobTableRows
    job_4f2a91events_daily1,204,330
    job_4f2a90orders88,412
    job_4f2a8esessions402,118

    sm

Title

  • JobTableRows
    job_4f2a91events_daily1,204,330
    job_4f2a90orders88,412
    job_4f2a8esessions402,118

    nonedefault

  • Jobs3
    JobTableRows
    job_4f2a91events_daily1,204,330
    job_4f2a90orders88,412
    job_4f2a8esessions402,118

    title

States

  • JobRows
    job_4f2a911,204,330
    job_4f2a9088,412
    job_4f2a8e402,118

    rest

  • JobRows
    job_4f2a911,204,330
    job_4f2a9088,412
    job_4f2a8e402,118

    hover

  • JobRows
    job_4f2a911,204,330
    job_4f2a9088,412
    job_4f2a8e402,118

    selected

  • JobTable
    job_4f2a91events_daily1,204,330
    job_4f2a8esessions402,118
    job_4f2a90orders88,412

    sorted

  • JobTableRows

    loading

  • JobTableRows

    No jobs match timeout.

    Clear the search to see every job.

    empty

Usage

When to use it
Use
A handful to a few hundred records a person compares across columns: jobs, partitions, tables, workers.
Use
Exact values that must line up: row counts, durations, bytes.
Not for
A job's output, line by line. Use Log viewer.
Not for
One record's nested fields. Use JSON view.

Rules

9 rules
Must
Give every Table a title or an aria-label. Because a screen reader announces an unnamed "table", and a page with two cannot be told apart in the tables list.
Must
Set numeric on the TableHead and every TableCell of a column of numbers, and give the column one unit. Because numeric right-aligns the column in Commit Mono, so the digits stack by place; 950ms beside 1.2s makes the eye compare the wrong digits.
Must
Set mono on cells holding an ID, a key or a path; never type-label or font-mono on a cell. Because mono sets type-code, 13px as written, level with the 14px sans; a label role would put the ID in capitals and change what it says.
Never
Tint a row or colour the text of its cells to show its outcome. Because colour in Sodium is status and always comes with a word, and a red row loses its meaning in forced colours and to a screen reader.
Never
Wrap a Table in a panel, a frame or another bordered box. Because the table is a frame already, and a box in a box is two edges where Sodium draws one.
Must
Show no rows with TableEmpty spanning every column, and loading with TableLoading, inside TableBody. Because the heads stay, so the columns do not jump when rows land, and the message sits where the first row would be.
Must
Make a column sortable with sort and onSort on its TableHead, never a click handler on the th. Because TableHead renders a real button and sets aria-sort, so the sort is reachable by Tab and announced with its direction.
Should
Put the selection Checkbox first, name each one with its row ("Select job_4f2a91"), and pass selected on the TableRow. Because the column keeps 40px and the selection wash, and "Select row 3" says nothing after a sort.
Should
Use size="sm" only for a table that shares the screen with other regions, such as a list beside a log. Because 32px rows fit more on screen but are a smaller target, and a table alone on its page has the room for 40.

State order

6 states, highest first
1
loading
2
empty
3
selected
4
open
5
hover
6
rest

Accessibility

5 checks
Name the table with title or aria-label; a scroll box that overflows takes a tab stop and the same name.
A sortable head is a button inside the th, which carries aria-sort ascending, descending or none.
Selected rows set aria-selected and the open row aria-current; the wash is never the only sign, the checkbox is ticked.
Heads are text-3 on the page, 5.6:1 in light; cells are text-1; the row rule is decoration and needs no contrast.
Set aria-busy on the Table while TableLoading shows; the placeholder rows are aria-hidden.

Keyboard

3 keys
Tab
Moves to the scroll box while it overflows, then to each sort button, checkbox and row action.
Enter
On a sort head, sorts; Space on a checkbox ticks it.
Arrow keys
In the focused scroll box, scroll it.

Edge cases

6 edge cases
Wider than its box
The rows scroll sideways inside the frame; the head and footer rows stay put.
Long value
Cells never wrap; the row scrolls sideways rather than break an ID.
Missing number
Write None in the cell; an empty cell reads as a rendering bug.
Last row
Drops the row rule; the frame's edge closes it.
Touch screen
Row actions and the unsorted sort mark always show, since nothing hovers.
Dark theme
The frame, panel and rules flip with their tokens; the selection wash turns into the dark yellow tint under text-1.

API

13 props
size
'default' | 'sm' default 'default'
title
ReactNode
count
ReactNode
actions
ReactNode
toolbar
ReactNode
footer
ReactNode
stickyHeader
boolean default false
maxHeight
number | string
TableHead numeric, sort, onSort
boolean, 'asc' | 'desc' | false, (event) => void
TableCell numeric, mono
boolean default false
TableRow selected, open
boolean
TableEmpty
{colSpan, title, description?, action?, reason?}
TableLoading
{rows?, columns}

Tokens

18 tokens
--page
#ffffff
--panel
#fafaf7
--line
#e2dfd5
--line-faint
#efede6
--hover
rgb(22 21 18 / 0.04)
--selected
#fff4bf
--selected-strong
#ffec99
--row
40px
--row-sm
32px
--control-sm
26px
--text-1
#161512
--text-2
#55524a
--text-3
#6b675e
--type-body-sm
400 14px/20px var(--font-sans)
--type-label
400 13px/16px var(--font-mono)
--type-label-sm
400 12px/16px var(--font-mono)
--type-code
400 13px/20px var(--font-mono)
--z-raised
10

Install

For your coding agent

GitHub

Please star me pookie

198

A new design system every week

Leave your email before you copy the prompt.