Usage
DataTable from @prepared911/ui-data-table is the system component for interactive tabular data. It pairs a scrollable grid with a filter region, a selection model, per-row menus, an optional expansion region, and a floating toolbar for bulk work. The mental model is "spreadsheet-like power with guardrails": operators refine the view, then act on many rows at once without leaving the table.
It is the default choice for incident lists, call queues, staff rosters, and any list view where users scan dense information, sort and filter aggressively, and invoke actions across a selection.
Menu columns and optional expansion for detail snippets.ResizableDrawer).Use a DataTable when the list is unbounded, paginated, or served from a cursor—dispatch incident history, call records, alert queues. Client sort/filter suits only bounded collections of a few hundred rows; beyond that, server-driven sort, filter, and pagination keep the grid responsive.
Use multiSelect when operators need to act on many rows at once (assign, update status, export). The floating toolbar reveals itself when selection is non-empty and lists applicable bulk actions. Disable selection on rows that cannot participate, don't hide them.
Per-row actions (open, assign, archive) belong in a compact menu column, rendered with Menu from @prepared911/ui-core through the row's action config. Keep the menu short (six items or fewer) and group with separators.
When a detail drawer shares horizontal space with the grid, the table reserves scroll width so users still reach columns that sit under the drawer. Pair with ResizableDrawer for widths the operator can control.
Table for light display of known-size data.DataTable is for tabular content; don't reach for it as a two-column layout wrapper.DataTable accepts column configs and optional slots:
showCheckboxes together with multiSelect, or showActionMenuTriggers together with actionMenu, when checkboxes or kebab triggers should remain visible without hovering (touch-heavy or sparse-hover layouts). The flags mirror to data-show-checkboxes and data-show-action-menu-triggers on the table root when active.fluidWidth when percentages and flex weights should dominate: fixed px/rem column sizes are folded into equal flex alongside other flex columns, and table minWidth / column maxWidth do not constrain layout. Root gets data-fluid-width. Omit for legacy pixel-stable layouts.formatMessage; "1 incident" / "24 incidents" must localize cleanly.Default sort is visually explicit (arrow + state). Sort changes trigger onSortingChange; for server-driven data, debounce and cancel stale requests. Announce the new sort direction in a polite live region so assistive tech users know the grid reordered.
Debounce search input (~300 ms) before firing server requests. Make applied filters visible in a chip row above the table, and give a single "Clear all" control that respects defaults. Never hide the only applied-filter indicator behind a tooltip.
When the filter region includes a reorderable columns menu, pass columnOrder to both Filter and DataTable so menu order and grid headers stay aligned. Visibility-only integrations can omit columnOrder; the columns menu then toggles visibility without drag handles. Column-order ids follow TanStack Table: explicit id, then accessorKey with dots replaced by underscores, then a string header.
Derive the initial reorderable order from the same visibility options passed to Filter; keep that order as the single source for both the menu and DataTable.
Show a skeleton on first paint; for partial refresh (paging, filter), use an inline loading indicator rather than replacing the grid. Keep the column header row stable so the eye doesn't reset.
Decide up front whether selection clears when the user pages; document the choice in the toolbar copy ("25 selected across all pages" vs "25 selected on this page"). select-all spanning pages should spell it out explicitly.
Guard destructive bulk work with a confirm step. Stream progress when the job is long (a Snackbar update with a running count beats a silent spinner). Handle partial failure by reporting the count that succeeded and the count that didn't.
When a Drawer is open, horizontal scroll should still expose obscured columns—verify at the narrowest layout your product supports. Pair with the columnVisibility config so operators can hide columns they're not reviewing.
Do
useMemo and avoid heavy work inside cell renderers.Don't
DataTable as a generic layout wrapper.Full semantic table structure, sortable headers with aria-sort, and keyboard paths for every toolbar and row action are covered in the Accessibility pages. The big rules: don't move focus unexpectedly after refresh, announce filter and sort changes politely, and keep the selection model visible in both the row and the toolbar.
DataTable.