Table
Lists records that share the same fields.
Sizes
Job Table Rows job_4f2a91 events_daily 1,204,330 job_4f2a90 orders 88,412 job_4f2a8e sessions 402,118 defaultdefault
Job Table Rows job_4f2a91 events_daily 1,204,330 job_4f2a90 orders 88,412 job_4f2a8e sessions 402,118 sm
Title
Job Table Rows job_4f2a91 events_daily 1,204,330 job_4f2a90 orders 88,412 job_4f2a8e sessions 402,118 nonedefault
- Jobs3
Job Table Rows job_4f2a91 events_daily 1,204,330 job_4f2a90 orders 88,412 job_4f2a8e sessions 402,118 title
States
Job Rows job_4f2a91 1,204,330 job_4f2a90 88,412 job_4f2a8e 402,118 rest
Job Rows job_4f2a91 1,204,330 job_4f2a90 88,412 job_4f2a8e 402,118 hover
Job Rows job_4f2a91 1,204,330 job_4f2a90 88,412 job_4f2a8e 402,118 selected
Job Table job_4f2a91 events_daily 1,204,330 job_4f2a8e sessions 402,118 job_4f2a90 orders 88,412 sorted
Job Table Rows loading
Job Table Rows 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'titleReactNodecountReactNodeactionsReactNodetoolbarReactNodefooterReactNodestickyHeaderbooleandefaultfalsemaxHeightnumber | stringTableHead numeric, sort, onSortboolean, 'asc' | 'desc' | false, (event) => voidTableCell numeric, monobooleandefaultfalseTableRow selected, openbooleanTableEmpty{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