Skip to content

DataGrid

X-03 · Composites · App components

All elements · DataGrid on the Composites page

Last checked 2026-10-22 · Awaiting approval · Accessibility tests

Copies the bun run a11y:approve command for DataGrid.

DataGrid

X-03WCAG 2.2 AA · Passed #447

Table plus column persistence, a column picker and infinite load. Adds a toolbar, a sticky-header scroll body, the picker popover and the load-more sentinel.

The specimen below is copied from datagrid.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-grid · __body · __sentinel · __drop-indicator regions and reorder feedback
.qf-column-picker List of toggles with drag handles
Grid with column picker (click "Columns")
Approve invoice INV-2026-0412 jdJane Doe Tomorrow High
Index batch Batch #2041 akAlex Kim Today Medium
Review contract MSA-2026 mrMaya Rossi 3 days Low
Assess claim CS-2041 Unassigned Next week High
Archive statements Finance / 2025 tsTom Sato Next month Low
Approve invoice INV-2026-0398 jdJane Doe Next month Medium
Verify identity Person 10442 akAlex Kim Next month Low
Loading more…
Columns

Guidance

When to use

  • Use it for a large, scrolling record set, such as a task queue of a thousand rows, where users scan and compare columns.
  • Use it when users choose, reorder and resize columns and expect those choices to persist.
  • Use it when rows load in pages as the user scrolls rather than through page buttons.
  • Use it when the column headers must stay visible while the body scrolls.

When to consider something else

  • Use a plain Table for a short, fixed data set that needs no column picker or infinite load. See Table.
  • Use Search with the table view when users also need a query, filters and a view switch. See Search.
  • Use a List when each record is a single line of text with an action, not a set of columns. See List.
  • Use Pagination instead of the load-more sentinel when users need to return to a known page. See Pagination.

Usability

Do
  • Show both the total and the loaded count in the toolbar, for example 1,204 rows · 40 loaded.
  • Keep the identifying column (Task in the reference) checked and disabled in the column picker so it cannot be hidden.
  • Give the column picker a Reset action that restores the default columns.
  • Show .qf-grid__sentinel with visible text (Loading more…) while the next rows load.
  • Right-align numeric columns and use aria-sort on the sorted header.
Don’t
  • Do not use infinite load when users must reach the footer or content below the grid.
  • Do not make drag the only way to reorder or resize columns.
  • Do not hide the column that names the row; every row needs a readable identifier.
  • Do not show status only by chip color; keep the text.

Accessibility

Keyboard

DataGrid keyboard
Keys Action
Tab Moves through the toolbar buttons, then the sortable header buttons, then focusable controls in the rows.
Enter or Space On a header's .qf-table__sort button, sorts by that column or reverses the order.
Enter or Space On Columns, opens the column picker; Escape closes it and returns focus to the button.
Space In the column picker, shows or hides the focused column.
Arrow keys If the binding adds cell navigation, it must follow the ARIA grid pattern: arrows move between cells, Home and End to row ends.

Roles and names

  • The grid is a native <table class="qf-table"> with <th scope="col"> headers inside .qf-grid__body; it stays a table unless the binding implements the full role="grid" pattern.
  • The sorted header carries aria-sort="ascending" or "descending"; other sortable headers omit it.
  • The toolbar is role="toolbar"; the Columns button carries aria-expanded and aria-controls, and the binding should add aria-haspopup="dialog".
  • The column picker is a popover holding a .qf-list of labeled checkboxes; drag handles are decorative and aria-hidden.
  • Resize handles (.qf-table__resize) are not focusable in the reference; the binding must expose a keyboard resize, such as a role="separator" with value attributes or a width field.

Focus

  • Loading more rows must not move focus; new rows append after the focused one.
  • Closing the column picker returns focus to the Columns button.
  • Sticky headers must not cover a focused row when the body scrolls (2.4.11).

Other requirements

  • The binding must announce when more rows have loaded, for example through a polite live region updating the loaded count (4.1.3).
  • Column reorder and resize by drag need a keyboard or single-pointer alternative, such as move up and move down actions in the picker (2.5.7).
  • The grid scrolls in both directions at narrow widths; 1.4.10 allows two-dimensional scrolling for data tables, but the toolbar must still reflow.
  • Header sort buttons and picker checkboxes must meet 24 by 24 CSS pixels (2.5.8).

Test your implementation too. This guidance covers the element as specified here. How a screen composes it (labels, order, announcements) still needs its own keyboard and screen reader check.

Accessibility tests

WCAG 2.2 AA · Passed

Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.

DataGrid test checklist
Area Automated A person checks
General Passed Color is never the only cue, text alternatives say the same thing as the graphic, and the element reads the same in the light and the dark theme.
Zoom Passed At 200% zoom, at 320 CSS pixels wide and with the WCAG text-spacing overrides, nothing is lost, clipped or overlapping.
Keyboard Passed Every row of the Keyboard table works, focus is always visible and never trapped, and the tab order follows the reading order. (5 rows)
Screen reader Passed With NVDA or JAWS on Windows and VoiceOver on macOS, names, roles and states are announced as Roles and names says, and changes are announced once. (5 items)

Approving. When the checklist passes on the checked run, record it with bun run a11y:approve -- datagrid --by "Your name" and commit a11y/approvals.json with the rebuilt pages. All test status

Package

Consumers link one stylesheet, css/classic/index.css, which includes every element. The files below are where this element is defined.

DataGrid package
Source css/classic/composites/data.css
Specimens also use Avatar · Box · Button · Card · Chip · Icon · List · ObjectDisplay · Popover · Search · Table · Text · Toggle · Toolbar
Sprites sprites/icons.svg
React Not yet available: the React binding has not started.

Latest updates

No recorded changes yet.

All release notes