Data grid
Sorts, selects and pages records from data.
Rows
- Runs12
run_8f28 support glaze-large 41.0s 38.9k Failed run_8f20 refund-agent glaze-large 9.0s 22.1k Failed run_8f25 refund-agent glaze-small 18.4s 12.8k Warning run_8f26 search glaze-large 0.6s 1.0k Running run_8f22 billing glaze-large None 0.0k Queued 12 rows, sorted by Status worst first, page 1 of 3
1–5 of 12 runs
pageddefault
- Runs12
run_8f2a refund-agent glaze-large 1.2s 4.8k Passed run_8f29 triage glaze-small 0.9s 1.2k Passed run_8f28 support glaze-large 41.0s 38.9k Failed run_8f27 billing glaze-small 2.2s 2.4k Passed run_8f26 search glaze-large 0.6s 1.0k Running run_8f25 refund-agent glaze-small 18.4s 12.8k Warning run_8f24 triage glaze-large 3.3s 5.1k Passed run_8f23 support glaze-small 0.9s 0.9k Passed run_8f22 billing glaze-large None 0.0k Queued run_8f21 search glaze-small 1.5s 1.7k Passed run_8f20 refund-agent glaze-large 9.0s 22.1k Failed run_8f1f triage glaze-small 0.8s 0.6k Passed 12 rows
scrolled
States
run_8f2a refund-agent glaze-large 1.2s 4.8k Passed run_8f29 triage glaze-small 0.9s 1.2k Passed run_8f28 support glaze-large 41.0s 38.9k Failed run_8f27 billing glaze-small 2.2s 2.4k Passed 4 rows
rest
run_8f28 support glaze-large 41.0s 38.9k Failed run_8f2a refund-agent glaze-large 1.2s 4.8k Passed run_8f29 triage glaze-small 0.9s 1.2k Passed run_8f27 billing glaze-small 2.2s 2.4k Passed 4 rows, sorted by Status worst first
sorted
run_8f2a refund-agent glaze-large 1.2s 4.8k Passed run_8f29 triage glaze-small 0.9s 1.2k Passed run_8f28 support glaze-large 41.0s 38.9k Failed run_8f27 billing glaze-small 2.2s 2.4k Passed 4 rows, 2 selected
selected
run_8f2a refund-agent glaze-large 1.2s 4.8k Passed run_8f29 triage glaze-small 0.9s 1.2k Passed run_8f28 support glaze-large 41.0s 38.9k Failed run_8f27 billing glaze-small 2.2s 2.4k Passed Loading rows
loading
No runs match timeout
0 rows
empty
Usage
When to use it
- Use
- Records from data that a person sorts, picks in bulk, pages through or trims to the columns they need.
- Use
- A run, key or deploy list on a phone, where the less important columns drop out by width.
- Use
- A long list in a fixed height: maxHeight sticks the heads, and rows past virtualizeFrom render only in view.
- Not for
- A short list written by hand, with no sorting or paging. Use Table.
- Not for
- Each record is one line of mixed content. Use Item.
Rules
9 rules
- Must
- Pass getRowId from a stable id, and rowName to name each row's checkbox. Because TanStack keys rows by index without it, so a selection lands on other rows after a sort or a new page of data, and "Select row 3" says nothing.
- Must
- Set meta.severity on a status column, and open with defaultSorting={[{id: 'status', desc: true}]} when the list is about what broke. Because sorted by the alphabet, Failed lands between Done and Passed, where a person scanning for trouble misses it.
- Must
- Give a column of durations or counts meta.unit and raw numbers, never preformatted strings. Because the grid picks one unit from the column's largest value and sorts by the number, while strings sort "9.0s" after "41.0s" and mix units.
- Should
- Give every column but the name, the main number and the status a meta.hideBelow, widest first to go. Because a phone then keeps the columns that answer the question, and the columns menu brings the rest back on demand.
- Must
- Set meta.mono on an ID, key or path column; never render a <code> or font-mono in the cell. Because meta.mono sets type-code-sm, 0.8 of the cells, so the wider Glaze Mono does not read a size bigger than its neighbours.
- Must
- Page rows the grid holds with pageSize and noun; for rows paged by the server, pass footer with PaginationInfo and PaginationNav size="sm". Because the range and the links sit on the shell's footer row, and a hand-made pager above the grid splits the record count from the records.
- Never
- Wrap a DataGrid in a Card or a bordered box; it brings the shell and panel, or takes frame="none" inside a Card's flush content. Because a card around the grid's card is two edges where one closes the group.
- Should
- Act on the selected rows with a BulkActionBar fed by rowSelection, above the grid or floating, never with buttons in each row. Because the bar names the count and clears with Escape, and per-row buttons repeat the same action down the page.
- Should
- Open a row with onRowClick and show which is open with activeRowId, apart from selection. Because the rows become one tab stop with arrow keys, and the open row takes aria-current without ticking a checkbox.
State order
6 states, highest first
- 1
- loading
- 2
- empty
- 3
- selected
- 4
- open
- 5
- hover
- 6
- rest
Accessibility
5 checks
- The table carries aria-label, aria-busy while loading and aria-rowcount for every row, paged or not.
- Each head is a sort button named "Duration, sorted descending. Sort", with aria-sort on the th; its menu button is named for the column.
- Checkboxes are named by rowName; the head one is "Select all rows" and shows mixed for some.
- A polite status line says the row count, the selection, the sort and the page after each change.
- Resize handles are separators with aria-valuenow, moved by the arrow keys; hiding a column moves focus to its neighbour.
Keyboard
4 keys
- Shift + click
- On a head, adds that column to the sort; on a checkbox, ticks or clears the range from the last one pressed.
- Arrow Left / Right
- On a resize handle, narrows or widens the column by 16px, 64px with Shift; Enter resets it.
- Arrow Up / Down, Home, End, Page Up / Down
- With onRowClick, moves between rows.
- Enter
- On a row with onRowClick, opens it.
Edge cases
6 edge cases
- Missing number
- A unit column shows None and leaves it out of the unit choice; it sorts last.
- Narrow grid
- Columns with hideBelow wider than the grid hide; one turned on in the columns menu stays.
- Reload
- The rows stay until the placeholders are due, so a fast refetch does not flash.
- Sort while paged
- Goes back to page 1; the selection is kept across pages.
- Head label longer than the column
- The column grows to fit its head, so no label is cut.
- Cut value
- The cell ends in an ellipsis and shows the whole value on hover.
API
17 props
columnsColumnDef<TData>[]dataTData[]getRowId(row, index) => stringrowName(row) => stringtitle, count, actionsReactNodetoolbar(table) => ReactNodepageSize, nounnumber, stringfooterReactNodeloading, loadingRowsboolean, numberdefaultfalse, 5emptyReactNodedefault'No rows'maxHeight, virtualizeFromnumber | string, numberdefault, 200sorting, defaultSorting, onSortingChangeSortingStatedefault[]rowSelection, onRowSelectionChangeRowSelectionStatedefault{}columnVisibility, defaultColumnVisibilityVisibilityStatedefault{}onRowClick, activeRowId(row) => void, stringrowActions, rowIndicator(row) => ReactNodeframe'card' | 'none'default'card'
Tokens
18 tokens
--shell- #f1f1f0
--paper- #ffffff
--line-faint- rgb(5 5 5 / 0.06)
--line- rgb(5 5 5 / 0.10)
--hover- rgb(5 5 5 / 0.06)
--pressed- rgb(5 5 5 / 0.10)
--field- #efefef
--row- 36px
--control-sm- 26px
--text-1- rgb(5 5 5 / 0.80)
--text-2- rgb(5 5 5 / 0.60)
--text-3- rgb(5 5 5 / 0.45)
--type-body-sm- 400 13px/1.5 var(--font-sans)
--type-label-sm- 500 12px/1.35 var(--font-sans)
--type-code-sm- 400 calc(13px * var(--mono-scale))/1.5 var(--font-mono)
--wait-show- 150ms
--wait-hold- 400ms
--z-raised- 10