Data Grid
import { DataGrid } from '@absoluteui/components/data-grid';import '@absoluteui/components/data-grid/style.css';Using Angular? See Data Grid for Angular.
What it does
Section titled “What it does”A spreadsheet-like ARIA grid for large and wide data.
-
Users move cell by cell with the keyboard; the grid is one Tab stop.
-
Rows and columns are virtualized in one native scroll container, so a million rows and hundreds of columns stay fast.
-
Column groups, pinning to either edge, resizing, moving, multi-sort, paging, and a saved view state are built in.
-
Column filters (text, number, BigInt, date with relative and business-day ranges, boolean, set) through a filter panel, an optional floating filter row, a quick filter with an optional search box, and an application filter.
-
An advanced filter: an expression bar with type-ahead suggestions (
[Name] contains "ann" and ([Age] >= 30 or [City] is any of ("Oslo", "Lima"))) and a builder dialog that edit the same tree of groups and conditions. -
Row selection: single or multiple, a checkbox column with a tri-state Select all (filtered rows, every row, or the page), click to select with Ctrl and Shift, and selectable rules; kept by row id.
-
Cell ranges: drag, Shift+arrows, Ctrl+A, several ranges with Ctrl, whole columns from the header; Ctrl+C copies ranges, selected rows, or the focused cell as Excel-compatible text and an HTML table.
-
Writes without mutating rows: paste (tiled over a range), cut, Delete, fill down and right (Ctrl+D, Ctrl+R), and a fill handle that continues number and date series (business days with a business calendar);
readOnlyEditsturns writes into requests the application applies. -
Cell editing: text, large text, number, date, date-time (in the grid’s time zone), select, checkbox, and custom editors; validation that blocks (or reverts) with an announced message; bulk edit of a range with Ctrl+Enter; undo and redo of every write; full-row editing with cross-field validation; batch editing with pending values; searchable list editors (one value or several, values loaded per query) in a separate entry point.
-
Row grouping: several levels, a generated group column with counts, aggregates (sum, min, max, count, avg, first, last, or custom) in group rows, group and grand totals, keyboard expansion as a treegrid; a group panel; date hierarchies (year, quarter, month, week, day); aggregates shown as percentages; group checkboxes that select a group’s rows; one group column or one per level.
Tree data, master/detail, pivot mode, and server row models are added in the next steps and phases of the Data Grid plan.
When to use
Section titled “When to use”- Large or wide data sets users explore cell by cell with the keyboard.
- Many columns that need pinning, groups, resizing, and reordering.
- Hundreds of thousands to millions of rows in the browser.
When not to use
Section titled “When not to use”- Read-mostly tables where every control is reached with Tab: use Data Table (plain table semantics).
- Page layout of non-tabular content: use Layout.
Examples
Section titled “Examples”Pinned and grouped columns over a million rows
Section titled “Pinned and grouped columns over a million rows”import { DataGrid, type DataGridSortChangeDetail } from '@absoluteui/components/data-grid';
interface Trade { id: string; symbol: string; price: number; qty: number;}
const rows: Trade[] = Array.from({ length: 1_000_000 }, (_, i) => ({ id: String(i), symbol: `S${String(i % 500)}`, price: (i % 997) / 10, qty: i % 300 }));const host = document.createElement('div');host.style.setProperty('block-size', '480px');document.body.append(host);const grid = DataGrid.create<Trade>(host, { label: 'Trades', rows, rowId: (r) => r.id, columns: [ { id: 'symbol', header: 'Symbol', field: 'symbol', pinned: 'start', width: 120 }, { id: 'deal', header: 'Deal', children: [ { id: 'price', header: 'Price', field: 'price', type: 'currency', currency: 'EUR' }, { id: 'qty', header: 'Quantity', field: 'qty', type: 'number', flex: 1 }, ] }, ],});grid.host.addEventListener('aui-sort-change', (event) => { console.log((event as CustomEvent<DataGridSortChangeDetail>).detail.sort);});Save and restore the view
Section titled “Save and restore the view”import { DataGrid } from '@absoluteui/components/data-grid';
const host = document.createElement('div');document.body.append(host);const grid = DataGrid.create(host, { label: 'People', rows: [{ id: 'a', name: 'Ada' }], rowId: (r) => r.id, columns: [{ id: 'name', header: 'Name', field: 'name' }], pageSize: 50,});grid.host.addEventListener('aui-columns-change', () => { localStorage.setItem('people-view', JSON.stringify(grid.getState()));});const saved = localStorage.getItem('people-view');if (saved) grid.setState(JSON.parse(saved));import { DataGrid, type DataGridCellActivateDetail } from '@absoluteui/components/data-grid';import '@absoluteui/components/data-grid/style.css';
interface Order { id: string; total: number;}
const host = document.querySelector<HTMLElement>('#orders');if (host) { DataGrid.create<Order>(host, { label: 'Orders', rows: [], rowId: (r) => r.id, columns: [{ id: 'total', header: 'Total', field: 'total', type: 'currency', currency: 'EUR' }] }); host.addEventListener('aui-cell-activate', (e) => { console.log((e as CustomEvent<DataGridCellActivateDetail<Order>>).detail.rowId); });}More usage
Section titled “More usage”import { DataGrid } from '@absoluteui/components/data-grid';
const host = document.createElement('div');host.style.setProperty('block-size', '400px');document.body.append(host);DataGrid.create(host, { label: 'People', rows: [{ id: '1', name: 'Ada', city: 'London' }], rowId: (r) => r.id, columns: [ { id: 'name', header: 'Name', field: 'name', pinned: 'start' }, { id: 'city', header: 'City', field: 'city', flex: 1 }, ],});Filtering: a filter kind per column, the floating filter row, and the search box. Restore filters from a URL with setState (validated).
import { DataGrid } from '@absoluteui/components/data-grid';
const host = document.createElement('div');host.style.setProperty('block-size', '400px');document.body.append(host);DataGrid.create(host, { label: 'People', rows: [{ id: '1', name: 'Ada', age: 36, city: 'London' }], rowId: (r) => r.id, floatingFilters: true, searchBox: true, filters: { age: { kind: 'number', conditions: [{ operator: 'greaterThanOrEqual', value: 30 }] } }, columns: [ { id: 'name', header: 'Name', field: 'name', filter: 'text' }, { id: 'age', header: 'Age', field: 'age', type: 'number', filter: 'number' }, { id: 'city', header: 'City', field: 'city', filter: 'set' }, ],});List editors (a separate entry point): a searchable list for one value and chips for several.
import { DataGrid } from '@absoluteui/components/data-grid';import { comboboxEditor, multiSelectEditor } from '@absoluteui/components/data-grid/editors';
interface Task { id: string; owner: string; tags: string[];}
const host = document.createElement('div');host.style.setProperty('block-size', '400px');document.body.append(host);DataGrid.create<Task>(host, { label: 'Tasks', rows: [{ id: '1', owner: 'Ada', tags: ['ui'] }], rowId: (r) => r.id, columns: [ { id: 'owner', header: 'Owner', field: 'owner', editable: true, editor: comboboxEditor({ values: [{ value: 'Ada', label: 'Ada' }, { value: 'Grace', label: 'Grace' }] }) }, { id: 'tags', header: 'Tags', field: 'tags', editable: true, editor: multiSelectEditor({ values: [{ value: 'ui', label: 'UI' }, { value: 'api', label: 'API' }] }), format: (v) => (Array.isArray(v) ? v.join(', ') : '') }, ],});Advanced filter: an expression bar and builder over the same model, here set from code.
import { DataGrid } from '@absoluteui/components/data-grid';
const host = document.createElement('div');host.style.setProperty('block-size', '400px');document.body.append(host);DataGrid.create(host, { label: 'People', rows: [{ id: '1', name: 'Ada', age: 36, city: 'London' }], rowId: (r) => r.id, advancedFilter: true, advancedFilterModel: { join: 'or', items: [ { column: 'age', filter: { kind: 'number', conditions: [{ operator: 'greaterThanOrEqual', value: 30 }] } }, { column: 'city', filter: { kind: 'set', values: ['Oslo', 'Lima'] } }, ], }, columns: [ { id: 'name', header: 'Name', field: 'name', filter: 'text' }, { id: 'age', header: 'Age', field: 'age', type: 'number', filter: 'number' }, { id: 'city', header: 'City', field: 'city', filter: 'set' }, ],});Anatomy
Section titled “Anatomy”<div class="aui-data-grid"> (consumer host, needs a height) <div class="aui-data-grid__toolbar"> <div role="search"> <label> Search <input type="search"> (searchBox: true) <div class="aui-data-grid__advanced" role="group"> (advancedFilter: true) <label>Filter</label> <input role="combobox"> <div role="listbox"> Apply Builder Clear error <div class="aui-data-grid__viewport"> one scroll container <div role="grid" aria-label aria-rowcount aria-colcount> <div role="rowgroup" class="aui-data-grid__head"> sticky header rows <div role="row"> <div role="columnheader"> ... (groups: aria-colspan; leaves may span rows) <button class="aui-data-grid__filter-button"> filterable leaves (tabindex -1) <div role="row" class="aui-data-grid__floating-row"> <div role="gridcell"> control (floatingFilters: true) <div role="rowgroup" class="aui-data-grid__body"> virtualized rows <div role="row" aria-rowindex> <div role="gridcell" aria-colindex> ... <div class="aui-data-grid__pager"> Pagination (when pageSize is set) <div class="aui-data-grid__overlay"> loading <div class="aui-data-grid__filter-panel" role="dialog"> open filter panel (top layer)</div><dialog class="aui-dialog aui-data-grid__builder-dialog"> builder (a modal Dialog in the document body)API reference
Section titled “API reference”Factory
Section titled “Factory”DataGrid.create<Row>(host: HTMLElement, options: DataGridOptions<Row>): DataGrid<Row>Global configuration key: dataGrid (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Accessible name of the grid. Required. | |
description |
string |
Accessible description of the grid (aria-describedby). | |
columns |
readonly (DataGridColumn<Row> | DataGridColumnGroup<Row>)[] |
Columns and column groups (nested). Column: id, header, accessor or field, type, currency, format, render, align, width, minWidth, maxWidth, flex, resizable, movable, pinned, lockPinned, lockPosition, hidden, sortable, compare, headerTooltip, wrapHeader, wrapText, rowDrag (this column holds the row drag handle; default the first data column), tooltip (true, a text, or (value, row) => text; with the tooltips accessory), spanRows (true or (a, b) => boolean: merge equal adjacent values), colSpan (row => columns covered), cellClass, cellClassRules, flashOnChange, copyValue, exportable, formula (a calculated column with the formulas option: [Column] is the same row, A1 references and functions as in spreadsheets; read-only), formulas (cell formulas: values that are text starting with = are evaluated; editing shows the formula; fill, Ctrl+D, and paste of copied cells move relative A1 references), excel (Excel export: style, cellStyle(row), numberFormat, formula(row, ref), link(row), image(row), width) (false leaves the column out of CSV and Excel exports of visible or all columns), aggregate, showAs, groupable, groupHierarchy, editable, setValue, parseValue, editor, required, validate, filter, filterValue, filterCaseSensitive, filterAccentSensitive, filterValues, businessCalendar, searchable, visibleWhen. Group: id, header, children, collapsible, collapsed, headerTooltip. Required. | |
rows |
readonly Row[] |
Row data (never mutated). Required. | |
rowId |
(row: Row) => string |
Stable, unique, non-empty id per row. Required. | |
rowHeight |
number | ((row: Row) => number) |
Row height in pixels (16 to 1000), or a function of the row. Default by density: 32, 40, or 48. | |
autoRowHeight |
boolean |
false |
Measure rendered rows and let them grow to their content (with wrapText columns); the scroll position stays anchored. |
layout |
'fill' | 'auto' |
"fill" |
fill: fills the host (which needs a height). auto: grows with its rows up to the host max-block-size. |
sort |
DataGridSort | readonly DataGridSort[] | null |
Current sort by priority: { column, direction: “ascending” | “descending” }. | |
pageSize |
number | null |
null |
Rows per page (1 to 1,000,000); null shows every row in one virtualized grid. |
pageSizes |
readonly number[] |
Offer a “Rows per page” choice with these sizes. | |
page |
number |
1 |
Current page, 1-based (clamped). |
filters |
DataGridFilters |
Active column filters by column id (JSON models: text, number, bigint, date with relative and business ranges, boolean, set). Validated; DATA_GRID_FILTER on malformed models. | |
quickFilter |
string |
Rows must contain every word in some searchable visible column (case- and accent-insensitive). | |
externalFilter |
(row: Row) => boolean |
Application filter applied with the others; call refreshFilters() when its result may change. | |
floatingFilters |
boolean |
false |
A header row of compact filter controls under the column headers: text contains, number syntax (5, >5, <=10, !=0, 5..10), date, boolean choice, set summary; complex filters show a read-only summary. |
searchBox |
boolean |
false |
A search box above the grid (role search) that sets the quick filter as the user types. |
advancedFilter |
boolean |
false |
An expression bar with type-ahead suggestions and a builder dialog replaces the column filter UI; column filters stop applying while it is on. |
advancedFilterModel |
DataGridAdvancedFilter | null |
The advanced filter: { join, items } of conditions { column, filter } and nested groups. Validated (DATA_GRID_FILTER); conditions on unknown columns are dropped. | |
rowSelection |
DataGridRowSelection<Row> | null |
Row selection: { mode: ‘single’ | ‘multiple’, checkboxes (default true; a checkbox column pinned first), headerCheckbox (default true), selectAll: ‘filtered’ (default) | ‘all’ | ‘page’, clickToSelect (default false), selectable(row) }. | |
selected |
readonly string[] |
Selected row ids (unknown and unselectable ids are dropped; kept by id across sort, filter, paging, and updates). | |
cellSelection |
boolean | DataGridCellSelection |
Cell ranges: drag, Ctrl+drag adds, Shift+click and Shift+arrows extend, Ctrl+A selects all; { multiple (default true), columnSelection (header Enter or click selects the column; sorting moves to Alt), fillHandle (drag the corner to fill a series; Alt repeats or counts; double-click fills down) }. | |
copyHeaders |
boolean |
false |
Copy column headers above copied cells. |
readOnlyEdits |
boolean |
false |
Writes (paste, cut, Delete, fill, edits) are only requested: aui-cells-change reports them with applied: false and the application applies them. |
clickToEdit |
boolean |
false |
A single click on an editable cell starts editing (otherwise Enter, F2, typing, Backspace, or a double-click). |
enterMovesDown |
boolean |
false |
Enter commits an edit and moves to the cell below. |
invalidEdit |
'block' | 'revert' |
"block" |
An invalid edit keeps the editor open with an announced message (block), or is discarded (revert). Focus leaving the editor discards an invalid value. |
undoLimit |
number |
20 |
Undo steps kept for edits, paste, cut, Delete, fill, and bulk edit (0 turns undo off); cleared when the application replaces or updates rows. |
editMode |
'cell' | 'row' |
"cell" |
row: editing opens every editable cell of the row; Tab moves within it; Enter commits the row as one write and one undo step. |
validateRow |
(values, row) => Record<string, string> | string | null |
Row mode: cross-field validation; a message (or messages by column) blocks the commit. | |
groupBy |
readonly string[] |
Group the rows by these columns (in level order). The grid becomes a treegrid with a generated group column (key, count, expansion); grouped columns hide (hideGroupedColumns). | |
groupDefaultExpanded |
number |
0 |
Levels expanded by default (0: all collapsed; -1: all expanded). |
groupTotals |
'bottom' | null |
A total row after each expanded group. | |
grandTotal |
'top' | 'bottom' | 'pinnedTop' | 'pinnedBottom' | null |
A grand total row at the top or bottom of the rows, or pinned above or below them (pinnedTop, pinnedBottom); flat grids too. | |
groupDisplay |
'column' | 'columns' | 'rows' |
"column" |
One generated group column indented by level, one per level (named after the grouped column; date parts in parentheses), or rows: group rows drawn as one cell across the row (no group column; not for tree data or pivot mode). |
stickyGroupRows |
boolean |
true |
While grouped, the group rows of the topmost row stay under the header as their groups scroll (copies hidden from assistive technology; their toggles work). |
fullWidthRow |
{ isFullWidth: (row: Row) => boolean; render: (row: Row, context: { doc, rowId }) => Node } | null |
Rows drawn as one cell across every column (it stays in view while the rows scroll sideways); never edited, filled, or part of ranges. | |
groupColumn |
{ header?: string; width?: number } |
Header text and width of the generated group column. | |
hideGroupedColumns |
boolean |
true |
Hide grouped columns while grouped. |
expanded |
Readonly<Record<string, boolean>> |
Group rows expanded or collapsed explicitly, by group id. | |
groupPanel |
boolean |
false |
A panel above the grid lists the row groups: move earlier, move later, remove, add a groupable column; dropping a groupable header on it groups by that column; pills can be dragged to reorder, or out of the panel to remove (the buttons are the keyboard path). |
aggregateFilteredOnly |
boolean |
true |
Aggregates use only the rows that pass the filters; false aggregates every row of each group. |
accessories |
readonly DataGridAccessory<Row>[] |
Accessories from @absoluteui/components/data-grid/accessories: columnMenu(), contextMenu(), columnChooser() (built on Context Menu and Dialog, outside the core bundle). The grid must be in the document when they attach. | |
headerNames |
Readonly<Record<string, string>> |
Header names set by the user, by column or column group id (part of the columns state as headers). | |
pinnedTopRows |
readonly Row[] |
Rows always shown above the body in a section named “Pinned to top” (never sorted, filtered, grouped, selected, or edited; at most 1000). | |
pinnedBottomRows |
readonly Row[] |
Rows always shown below the body in a section named “Pinned to bottom”. | |
pinned |
Readonly<Record<string, "top" | "bottom">> |
Rows pinned to the top or bottom by id (they also stay in the body; filters hide the pinned copy). | |
formulas |
DataGridFormulaEngine |
The formula engine for calculated columns: formulaEngine({ functions?, calendar? }) from @absoluteui/components/data-grid/formulas (our own parser and evaluator; no eval). Results recalculate when rows change; errors show their code (#DIV/0!, #REF!, …) with the meaning read out. | |
fileDrop |
{ onFiles: (files) => void; accept?: string[]; label?: string } |
Files dropped on the grid: an overlay (aui-data-grid__file-drop, default text “Drop files to load”) shows while files are over it; files matching accept (extensions such as .csv, MIME types such as text/csv or text/*; default all) go to onFiles, others are announced. Pointer only: offer a file input too. With parseCsv from @absoluteui/helpers/csv, coerceCsvValues, and inferColumns an app can load a dropped CSV with generated columns. | |
rowDragging |
boolean | { managed?: boolean; multiRow?: boolean; canDrag?: (row) => boolean; nativeData?: (rows) => Record<string, string> } |
false |
Row dragging: a drag handle in the rowDrag column (pointer: a drop line, or a target row in parent-id tree data), and Ctrl+Shift+ArrowUp / ArrowDown on a handle cell (in trees Ctrl+Shift+ArrowRight / ArrowLeft indent and outdent); announced. managed: the grid moves the rows (one undo step) while not sorted, filtered, grouped, pivoted, or server-side; multiRow: dragging a selected row drags every selected row; canDrag limits the rows. nativeData: the handle uses native drag and drop and the drag carries that data (MIME type to text) to other apps; drops on the rows and on zones work as with the pointer. Drop zones: addRowDropZone, rowDropZone. |
rowNumbers |
boolean | { width?: number; resizable?: boolean } |
false |
A leading column numbering the rows by display position (width 32 to 200, default 56); with cell ranges a click on a number selects the row’s cells; resizable adds a handle (drag, or Alt+ArrowUp / Alt+ArrowDown on the number) that sets the row’s height. |
datasource |
DataGridDatasource<Row> | null |
Server row model: { getRows(request, signal) => Promise<{ rows, rowCount? }> } (request: start, end, sort, filters, quickFilter, advancedFilter, groupBy, groupKeys); with groupBy the top level loads group rows and each expanded group loads its own rows; rows load in blocks as they scroll into view, and sort, filters, the quick filter, and the advanced filter run on the server (rows is ignored; pass []). An unknown rowCount grows block by block until a short block. | |
blockSize |
number |
100 |
Rows per datasource request (1 to 10000). |
maxBlocks |
number | null |
null |
Loaded blocks kept; the least recently used are released (null keeps all). |
blockLoadDelay |
number |
50 |
Milliseconds to wait before loading while scrolling (0 to 5000). |
maxConcurrentLoads |
number |
2 |
Datasource requests at a time (1 to 20). |
initialRowCount |
number |
0 |
Rows assumed before the first answer (the scrollbar size). |
getChildCount |
(row: Row) => number | null |
Server groups: the number of rows below a group row (shown with its key); null when unknown. | |
purgeClosedGroups |
boolean |
false |
Server groups: collapsing a group releases its loaded rows (they load again when it expands). |
pivot |
DataGridPivot | null |
Pivot mode: { rows, columns, values: [{ column, aggregate: sum | count | avg | min | max | distinctCount }] }; rows group by the row fields, a column group per column key holds a result column per value, with total columns; the data columns hide. | |
pivotPanel |
boolean |
false |
A panel above the grid edits the pivot: rows, columns, and values zones with pills (move, remove; an aggregate per value) and pickers; pills can be dragged within and between zones (a value keeps its aggregate, a new value gets sum or count) or out of the panel to remove. |
pivotMaxColumns |
number |
1000 |
Most generated pivot result columns (1 to 100000); more are left out, announced, and reported by getPivotTruncation(). |
detail |
DataGridDetail<Row> | null |
Master/detail: { render(row, { doc, rowId }) => Node, height (px, default 300, or auto), isMaster(row), keep (collapsed details kept, default 10), expandedByDefault, destroy(node, row) }; a generated toggle column expands a detail row under each master row. | |
treeData |
DataGridTreeData<Row> | null |
Tree data: exactly one of serverGroup with serverKey (with a datasource: parents load their children from the server when expanded), getPath (row => string[]; missing levels become filler rows), parentIdField (self-referential; missing parents and cycles become root rows), or childrenField (nested rows); label names the column that labels rows in the group column. groupBy is ignored. | |
treeFilter |
"ancestors" | "subtree" |
"ancestors" |
Filtering keeps the ancestors of matching rows; subtree also keeps the rows below a matching row. |
flashChanges |
boolean |
false |
Highlight cells whose displayed text changes when rows are updated (setRows, transactions); columns can opt in with flashOnChange. |
flashDuration |
number |
800 |
Milliseconds a changed cell stays highlighted (100 to 10000). |
rowClassRules |
Readonly<Record<string, (row: Row) => boolean>> |
Classes added to a row while their predicate is true (re-evaluated on every render). | |
loading |
boolean |
false |
Busy state: aria-busy and an announced loading overlay; rows stay in place. |
emptyMessage |
string |
Text of the single grid cell shown when there are no rows. Default “No rows to show”. | |
multiSort |
boolean |
true |
Shift+click and Shift+Enter add a column to the sort. Globally configurable. |
sortCycle |
'tri-state' | 'bi-state' |
"tri-state" |
tri-state: ascending, descending, unsorted. bi-state: ascending, descending. Globally configurable. |
overscan |
number |
8 |
Rows rendered beyond each edge of the viewport (0 to 200). Globally configurable. |
transactionDelay |
number |
50 |
Milliseconds between applying queued applyTransactionAsync batches (0 to 10000). Globally configurable. |
animateRows |
boolean |
true |
Rows glide to their new position after a sort or update (off with reduced motion or animation none). Globally configurable. |
filterDelay |
number |
250 |
Milliseconds after typing stops before a typed filter value applies (0 to 10000); Enter applies at once. Globally configurable. |
maxFilterConditions |
number |
2 |
Conditions offered per text, number, and date filter in the filter panel (1 to 10). Globally configurable. |
locale |
string |
"en-US" |
Formatting, collation, and messages locale. Globally configurable. Inherited from common configuration. |
timezone |
string |
"UTC" |
IANA time zone for datetime columns. Globally configurable. Inherited from common configuration. |
density |
'compact' | 'comfortable' | 'spacious' |
"comfortable" |
Row and header heights and cell padding. Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
Layout direction (pinned sides, arrow keys, resizing mirror). Globally configurable. Inherited from common configuration. |
icons |
Partial<DataGridIcons> |
Icon slot overrides (sortAscending, sortDescending, sortNone, expand, collapse, loading, filter, drag). |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer-provided host (children are owned by the grid). |
element |
HTMLDivElement |
The element with role=“grid”. |
rowCount |
number |
Rows displayed (the current page when paging). |
sort |
DataGridSort[] |
Current sort by priority (a copy). |
focusedCell |
DataGridCellPosition | null |
The cell or header holding the tab stop: { rowId, column } or { rowId: null, column, level }. |
filteredRowCount |
number |
Rows that pass the filters (before paging). |
editingCell |
{ rowId, column } | null |
The cell being edited. |
canUndo |
boolean |
An undo step is available. |
canRedo |
boolean |
A redo step is available. |
isBatchEditing |
boolean |
A batch is collecting pending values. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
update(options: Partial<DataGridOptions<Row>>): void |
Merge and apply options. |
setRows(rows: readonly Row[]): void |
Replace the rows; sort, focus, and scroll position are kept. |
applyTransaction(tx: DataGridTransaction<Row>): DataGridTransactionResult |
Add, update (by id), and remove (by id) rows; sort is re-applied and rows keep their identity. Emits aui-rows-change; unknown ids are reported in missing. |
applyTransactionAsync(tx: DataGridTransaction<Row>): void |
Queue a transaction; queued ones are applied together every transactionDelay ms. |
flushTransactions(): void |
Apply queued transactions now. |
getFilters(): DataGridFilters |
Active column filters (copies). |
setFilter(column: string, filter: DataGridFilter | null): void |
Set or clear one column filter (validated; emits nothing). |
setQuickFilter(text: string): void |
Set the quick filter text (emits nothing). |
refreshFilters(): void |
Re-run the filters (for example after the external filter changed). |
getAdvancedFilter(): DataGridAdvancedFilter | null |
The advanced filter model (a copy). |
setAdvancedFilter(filter: DataGridAdvancedFilter | null): void |
Set or clear the advanced filter model (validated; emits nothing). |
getSelected(): string[] |
Selected row ids, in source order. |
getSelectedRows(): Row[] |
Selected rows, in source order. |
setSelected(ids: readonly string[]): void |
Replace the selection (validated; emits nothing). |
selectAll(scope?: 'filtered' | 'all' | 'page'): void |
Select every selectable row in the scope (default: rowSelection.selectAll; emits nothing). |
clearSelection(): void |
Clear the selection (emits nothing). |
getCellRanges(): DataGridCellRange[] |
Cell ranges (copies), the active one last. |
addCellRange(range: DataGridCellRange): void |
Add a range of displayed rows and visible columns (validated; emits nothing). |
clearCellRanges(): void |
Clear the cell ranges (emits nothing). |
copySelection(): Promise<string> |
Copy the ranges, else the selected rows, else the focused cell, with the asynchronous Clipboard API; returns the tab-separated text. |
startEditing(rowId: string, column: string): boolean |
Start editing a displayed, editable cell. |
stopEditing(cancel?: boolean): void |
Commit the open edit (an invalid value is discarded) or cancel it. |
undo(): boolean |
Undo the last applied write or managed row move. |
redo(): boolean |
Redo the last undone write. |
startBatch(): void |
Collect writes as pending values (shown and spoken as edited; sorting and filtering keep committed data). |
commitBatch(): void |
Apply the pending values as one transaction and one undo step (source batch). |
cancelBatch(): void |
Discard the pending values. |
expandAll(): void |
Expand every group row (emits nothing). |
collapseAll(): void |
Collapse every group row (emits nothing). |
setExpanded(groupId: string, expanded: boolean): boolean |
Expand or collapse one group row (emits nothing). |
getGroups(): DataGridGroup[] |
The current groups: ids, columns, keys, counts, aggregates, and children. |
moveRow(id: string, parentId: string | null, index: number): boolean |
Tree data with parentIdField: move a row under another parent (null: a root) at a position among its new siblings; the row is a shallow copy (never mutated); false for unknown ids, moves into its own subtree, and other tree modes. Emits aui-rows-change. |
alignWith(other: DataGrid<Other>): () => void |
Keep another grid’s columns (order, widths, pinning, visibility, collapsed groups) and horizontal scroll in step with this one, both ways (for example a totals grid under the main grid); the other grid takes this grid’s columns now. Returns a function ending it; destroying either grid ends it. |
addRowDropZone(zone: DataGridRowDropZone<Row>): () => void |
Let rows dragged from this grid drop on an element outside it: { element, label, onDrop, onDragEnter?, onDragMove?, onDragLeave? }, each called with { rowIds, rows, x, y, grid }. The element gets aui-data-grid-drop-zone–active while rows are over it; the cell menu’s Send to submenu lists zones by label (the keyboard path, x and y null). Returns a function removing the zone. |
rowDropZone(options?: { label?: string; move?: boolean }): DataGridRowDropZone<Row> |
A zone for another grid’s addRowDropZone adding the dropped rows to this grid (at the drop line when its rows are in source order, else at the end; ids already present are skipped); move removes the added rows from the source grid. |
setColumnHeader(id: string, header: string | null): boolean |
Rename a column or column group (null restores its defined header); false for unknown ids. Emits aui-columns-change (rename). |
resetColumns(): void |
Undo the user’s column changes (order, widths, pinning, visibility, collapsed groups, names). Emits aui-columns-change (reset). |
pinRow(rowId: string, side: "top" | "bottom" | null): boolean |
Pin a row by id to the top or bottom, or unpin it; false for unknown ids (emits nothing). |
getPinnedRows(): { top: string[]; bottom: string[] } |
Ids of the rows pinned by id, by section, in pin order. |
setRowHeight(rowId: string, height: number | null): void |
Set a row’s height in px (16 to 2000), or null for its default height (emits nothing). |
applyServerTransaction(tx: DataGridServerTransaction<Row>): DataGridTransactionResult |
Server row model: apply changes the server already holds to the loaded rows (add at addIndex, update, remove by id; later rows shift; rowCount corrects the total); rows that are not loaded are reported missing. Emits aui-rows-change. |
getServerSelection(): { selectAll: boolean; toggled: string[] } |
Server row model: the selection state; with selectAll, toggled lists the rows not selected. |
setServerSelection(state: { selectAll: boolean; toggled: string[] }): void |
Server row model: set the selection state (multiple selection only; emits nothing). |
refresh(options?: { purge?: boolean; route?: readonly unknown[] }): void |
Server row model: reload the loaded blocks; purge drops them first (loading rows show). |
retryLoads(): void |
Server row model: load failed blocks again (never done automatically). |
setRowCount(count: number, known?: boolean): void |
Server row model: set the row count; known false keeps growing it as blocks arrive. |
isRowCountKnown(): boolean |
Server row model: whether the total row count is known (always true for client rows). |
getPivot(): DataGridPivot | null |
Pivot mode: the current pivot, or null. |
setPivot(pivot: DataGridPivot | null): void |
Pivot mode: set the pivot; null leaves pivot mode (emits nothing). |
getPivotTruncation(): { shown: number; total: number } | null |
Pivot mode: result columns shown and in total when pivotMaxColumns left some out, else null. |
setDetailExpanded(rowId: string, expanded: boolean): boolean |
Master/detail: expand or collapse a master row’s details; false for rows without details (emits nothing). |
isDetailExpanded(rowId: string): boolean |
Master/detail: whether a master row’s details are expanded. |
getTreeOrphans(): string[] |
Tree data: ids of rows whose parent is missing or would form a cycle (shown as root rows). |
toCsv(options?: DataGridCsvOptions<Row>): string |
RFC 4180 CSV with formula-injection protection (text starting with =, +, -, @, a tab, or a carriage return is prefixed with a quote; numbers the grid formats itself are trusted). Options: columns (visible, all, or ids), rows (filtered: across pages with group rows and totals, every group expanded; page; selected and all, ignoring filters; range: the active cell range), groups (rows or none), header, columnGroups (group rows above the header), pinned, values (formatted or raw), indent (per level for group and tree labels), delimiter, lineEnding, bom, escapeFormulas, and value(cell) for custom values. With a datasource only loaded rows exist. |
toCsvBlob(options?: DataGridCsvOptions<Row>): Blob |
toCsv() as a text/csv Blob; downloadCsv from the Data Table entry saves it. |
cellAddress(rowId: string, column: string): string | null |
A cell’s stable A1 address for formulas (column letters by column definition order, row numbers by source row order), or null without formula columns. |
cellFormula(rowId: string, column: string): string | null |
A cell’s formula: the calculated column’s formula or the cell formula; null for plain values. |
getExportData(options?: DataGridExportOptions): DataGridExportData<Row> |
The rows and columns of an export for exporters such as toXlsx in @absoluteui/components/data-grid/export: the toCsv choices (columns, rows, groups, pinned), raw values (aggregates as numbers), display text (text: “needed” formats only where required), group levels, column group header runs, and the expansion state. No side effects. |
print(options?: DataGridPrintOptions): void |
Print the rows as a static table shown only in print media (the page itself is hidden while printing): the toCsv row and column choices (columns, rows, groups, pinned), a title (default: the grid label) as the caption, column group headers repeated on every page, group and total rows, the grid direction, and print colors. The table is removed after afterprint. More than 20,000 rows throws DATA_GRID_PRINT (page the grid or export CSV). |
getState(): DataGridState |
Serializable view state: sort, columns (order, widths, pinned, hidden, collapsed groups), page, page size; includes details (master rows expanded or collapsed), pinnedRows (pinned by id), and pivot. |
setState(state: unknown): void |
Restore a view state; untrusted input is validated (DATA_GRID_STATE), unknown ids are dropped; emits nothing. |
getColumnsState(): DataGridColumnsState |
The columns section of the state. |
moveColumn(id: string, target: string, position?: 'before' | 'after'): boolean |
Move a column or group next to a sibling with the same parent group. |
setColumnPinned(id: string, pinned: DataGridPinned | null): boolean |
Pin to the start or end edge, or unpin. |
setColumnHidden(id: string, hidden: boolean): boolean |
Hide or show a column (one always stays visible). |
autoSizeColumns(ids?: readonly string[]): void |
Size columns to their header and rendered cells. |
fitColumns(): void |
Scale the visible columns to the viewport width. |
focusCell(rowId: string, column: string): boolean |
Move focus to a cell, scrolling it into view. |
scrollToRow(rowId: string): boolean |
Scroll a row into view. |
scrollToColumn(column: string): boolean |
Scroll a column into view. |
destroy(): void |
Remove the grid, listeners, and released nodes. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-sort-change |
{ sort: DataGridSort[] } |
Yes | No | The user changed the sort. |
aui-rows-change |
{ added, updated, removed, missing } |
Yes | No | A transaction (sync or batched) changed the rows. |
aui-filter-change |
{ filters, quickFilter, advancedFilter } |
Yes | No | The user changed a column filter, the quick filter, or the advanced filter; the row count is announced. |
aui-columns-change |
{ reason, columns: DataGridColumnsState } |
Yes | No | The user (or a method) resized, moved, pinned, hid, auto-sized, or fitted columns, or toggled a column group. |
aui-page-change |
{ page, pageSize } |
Yes | No | The user changed the page or the page size. |
aui-cell-focus |
{ rowId: string | null, column } |
Yes | No | Focus moved to another cell or header. |
aui-cell-activate |
{ rowId, column, row } |
Yes | No | Enter on a cell without widgets, or a double click. |
aui-selection-change |
{ selected, added, removed, reason } |
Yes | No | The user changed the row selection (‘user’, ‘select-all’), or selected rows were removed (‘rows’); the count is announced for user changes. |
aui-range-change |
{ ranges, finished } |
Yes | No | The user changed the cell ranges (finished is false while a drag extends the range). |
aui-cells-change |
{ changes: [{ rowId, column, oldValue, newValue }], source, applied, rejected } |
Yes | No | Cells were written by an edit, bulk edit, paste, cut, Delete, fill, undo, or redo (one transaction; with readOnlyEdits only requested, applied: false); rejected lists pasted text a column could not convert. |
aui-row-group-toggle |
{ groupId, expanded } |
Yes | No | The user expanded or collapsed a group row (announced with its row count). |
aui-group-change |
{ groupBy } |
Yes | No | The user changed the row groups in the group panel (announced). |
aui-detail-toggle |
{ rowId, expanded } |
Yes | No | The user expanded or collapsed a master row’s details (announced). |
aui-row-pin |
{ rowId, pinned } |
Yes | No | The user pinned or unpinned a row (announced). |
aui-row-drag-start |
{ rowIds } |
Yes | No | The user started dragging rows with a drag handle. |
aui-row-drop |
{ rowIds, targetId, position, source } |
Yes | Yes | Rows were dropped before, after, or (tree data) inside a target row, by pointer or keyboard; cancel to keep the order. Managed grids then move the rows. |
aui-row-resize |
{ rowId, height } |
Yes | No | The user resized a row with its row number handle (announced). |
aui-pivot-change |
{ pivot } |
Yes | No | The user changed the pivot in the pivot panel (announced). |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-data-grid |
Host; aui-data-grid–compact / –spacious / –auto modifiers. |
aui-data-grid__viewport |
The single scroll container (both axes). |
aui-data-grid__head | __header-row | __header-cell | __group-header |
Sticky header rows, leaf and group header cells. |
aui-data-grid__body | __row | __cell |
Virtualized rows and cells; __cell–end / –center alignment, –wrap, –pinned-start / –pinned-end. |
aui-data-grid__resize | __drop-indicator |
Column resize handle and column drop position. |
aui-data-grid__overlay | __empty | __pager |
Loading overlay, empty-state cell, pagination host. |
aui-data-grid__filter-button | __header-cell--filtered |
Filter button in filterable headers (–active while filtered) and the filtered header state. |
aui-data-grid__filter-panel |
The filter panel (non-modal dialog in the top layer): __filter-title, __filter-form, __filter-condition, __filter-join, __filter-set, __filter-values, __filter-clear. |
aui-data-grid__floating-row | __floating-cell | __floating-control |
Floating filter row, its cells, and their compact controls. |
aui-data-grid__toolbar | __search | __search-input |
Toolbar (role search) with the quick filter search box. |
aui-data-grid__advanced | __advanced-input | __advanced-list | __advanced-option | __advanced-error |
Advanced filter expression bar: combobox field, suggestion listbox, and error message. |
aui-data-grid__builder-dialog | __builder-group | __builder-condition | __builder-tools |
Builder dialog (a Dialog): groups as fieldsets, condition rows, item buttons. |
aui-data-grid__row--selected | __select-input | __select-all | __select-header |
Selected rows, row checkboxes, the Select all checkbox, and the selection column header. |
aui-data-grid__cell--range | --range-top | --range-bottom | --range-start | --range-end |
Cells inside cell ranges and the range edges. |
aui-data-grid__fill-handle | __cell--fill |
The fill handle in the range corner and the cells a fill drag would cover. |
aui-data-grid__cell--editing | __editor | __editor--popup | __editor-control | __edit-error |
The edited cell, the editor (inline or a popup over the cell), its control, and the validation message. |
aui-data-grid__row--editing | __cell--pending |
The row edited in row mode, and cells with pending batch values. |
aui-data-grid__row--group | __row--total | __group-cell | __group-toggle |
Group and total rows, the group column cell (indented by level), and the expansion toggle. |
aui-data-grid__group-panel | __group-panel--drop | __group-pill | __group-pill-button | __group-add |
The group panel, its drop state, pills and their buttons, and the add picker. |
aui-data-grid__select-group |
A group row checkbox (tri-state over its rows). |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
sortAscending |
arrow-up |
sortDescending |
arrow-down |
sortNone |
arrow-up-down |
expand |
chevron-right |
collapse |
chevron-down |
loading |
spinner |
filter |
filter |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-hover | --aui-color-info-fg | --aui-color-primary | --aui-color-selected | --aui-color-selected-text | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-color-warning-fg | --aui-color-warning-subtle | --aui-control-height-sm | --aui-duration-fast | --aui-duration-normal | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-mono | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xs | --aui-font-weight-medium | --aui-font-weight-regular | --aui-font-weight-semibold | --aui-icon-size-md | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-space-4 | --aui-space-6
TypeScript definitions
Section titled “TypeScript definitions”interface DataGridSort { column: string; direction: 'ascending' | 'descending' }interface DataGridState { version: 1; sort: readonly DataGridSort[]; columns: DataGridColumnsState; page: number; pageSize: number | null; filters?: DataGridFilters; quickFilter?: string; advancedFilter?: DataGridAdvancedFilter | null; selected?: readonly string[]; groupBy?: readonly string[]; expanded?: Readonly<Record<string, boolean>> }interface DataGridCellRange { startRow: string; endRow: string; startColumn: string; endColumn: string }interface DataGridGroup { id: string; column: string; key: unknown; count: number; aggregates: Record<string, unknown>; children: DataGridGroup[] }interface DataGridCellChange { rowId: string; column: string; oldValue: unknown; newValue: unknown }interface DataGridCellEditor { element: HTMLElement; getValue(): unknown; focus(): void; control?: HTMLElement; popup?: boolean; destroy?(): void }interface DataGridRowSelection<Row> { mode: 'single' | 'multiple'; checkboxes?: boolean; headerCheckbox?: boolean; selectAll?: 'filtered' | 'all' | 'page'; clickToSelect?: boolean; selectable?: (row: Row) => boolean }interface DataGridAdvancedFilter { join: 'and' | 'or'; items: readonly (DataGridAdvancedCondition | DataGridAdvancedFilter)[] }interface DataGridAdvancedCondition { column: string; filter: DataGridFilter }type DataGridFilter = DataGridTextFilter | DataGridNumberFilter | DataGridBigIntFilter | DataGridDateFilter | DataGridBooleanFilter | DataGridSetFilter;interface DataGridTextFilter { kind: 'text'; join?: 'and' | 'or'; conditions: readonly { operator: DataGridTextOperator; value?: string }[] }type DataGridColumnDef<Row> = DataGridColumn<Row> | DataGridColumnGroup<Row>;Accessibility
Section titled “Accessibility”Pattern: WAI-ARIA APG Grid pattern: one tab stop, roving focus between cells and headers, arrow-key navigation, widgets inside cells reached with Enter or F2.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Arrow keys | Cell or header | Move one cell; Up from the first row enters the headers; Down from the headers enters the first row. |
| Home / End | Cell | First / last cell of the row. |
| Ctrl+Home / Ctrl+End | Cell | First cell of the first row / last cell of the last row. |
| PageUp / PageDown | Cell | Move a page of rows. |
| Enter / F2 | Cell with widgets | Move focus into the first widget; Escape or F2 returns to the cell. |
| Enter | Cell without widgets | Activates the cell (aui-cell-activate). |
| Enter / Space (Shift adds) | Sortable header | Sorts (Shift: multi-sort). |
| Enter / Space | Collapsible group header | Expands or collapses the group. |
| Shift+ArrowLeft / Right | Header | Moves the column or group (announced). |
| Alt+ArrowLeft / Right (Shift: larger steps) | Header | Resizes the column by 10 px (50 px), announced. |
| Tab / Shift+Tab | Any | Leaves the grid (one tab stop). |
| Element | Role |
|---|---|
| grid container | grid (aria-label, aria-rowcount, aria-colcount) |
| header and body containers | rowgroup |
| rows | row (aria-rowindex) |
| header cells | columnheader (aria-colindex, aria-sort, aria-colspan for groups, aria-rowspan for spanning leaves, aria-expanded for collapsible groups) |
| cells | gridcell (aria-colindex) |
| spacers, fillers, resize handles, drop indicator | none (aria-hidden) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-rowcount / aria-colcount |
grid | Full counts (header rows plus displayed rows; visible columns), including rows and columns not rendered |
aria-rowindex / aria-colindex |
rows / cells | 1-based positions in the full grid |
aria-sort |
primary sorted column header | ascending | descending; other sort levels are spoken as “sort priority n” |
aria-busy |
grid | true while loading |
aria-describedby |
grid | The description option |
One tab stop on the focused cell or header (initially the first header). The focused row and column stay rendered while scrolled away, so focus is never lost to virtualization.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- Sort changes, column moves and resizes, group toggles, and loading are announced through the shared polite live region.
- Pinned columns are sticky cells in DOM order, so reading order matches the visual order in both directions.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver, TalkBack) is pending.
- Pointer resizing needs a drag; keyboard and API alternatives exist (WCAG 2.5.7).
Behavior
Section titled “Behavior”States
Section titled “States”default, empty, no matching rows, loading, cell focused, header focused, sorted, multi-sorted, filtered, filter panel open, advanced filter error, builder open, rows selected, cell ranges, editing, edit invalid, row editing, batch pending, grouped, group expanded, column resizing, column dragging, group collapsed, paged.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| unsorted | header click or Enter | ascending, then descending, then unsorted (tri-state) |
| sorted | Shift+click or Shift+Enter on another header | multi-sorted (added with the next priority) |
| expanded group | Enter or click on a collapsible group header | collapsed (children with visibleWhen switch) |
| any page | Pagination | another page (aui-page-change), scrolled to the top |
| unfiltered | a value typed in the panel, a floating filter, or the search box (after filterDelay; Enter at once), or a choice made |
filtered (aui-filter-change, row count announced), first page, scrolled to the top |
| filtered | Clear filter, an emptied value, or all set values selected | unfiltered |
| panel closed | filter button, Alt+ArrowDown on a header or floating cell, Enter on a read-only floating summary | panel open (focus on its first control) |
| panel open | Escape | closed, focus back on the header (or the floating control that opened it) |
| panel open | focus or pointer outside the panel | closed, pending typed value applied |
| row not selected | checkbox, Space, or (clickToSelect) click | selected (aui-selection-change, count announced); single mode deselects the previous row |
| rows selected | Shift+checkbox, Shift+Space, or Shift+click | the range from the last toggled row is added |
| any | header checkbox, Space on the selection header, or Ctrl+A | every selectable row in the Select all scope selected (or cleared) |
| no range | press and drag over cells, Shift+arrows, or Ctrl+A (cell selection) | a cell range (aui-range-change; size announced) |
| ranges | Ctrl+drag / Shift+click / a plain arrow key | another range added / the active range extended / ranges cleared |
| any | Ctrl+C on a cell | ranges (stacked), else selected rows, else the focused cell copied; announced |
| editable cell | Enter, F2, a printable key (replaces the value), Backspace (empty), double-click, or (clickToEdit) a click | editing |
| editing | Enter / Tab, Shift+Tab / Escape / focus leaving | committed (focus back on the cell; enterMovesDown moves down) / committed and the next or previous editable cell edited / cancelled / committed |
| editing | an invalid value committed | blocked: message under the cell, aria-invalid, announced (invalidEdit: 'revert' discards instead; focus leaving discards) |
| group collapsed | ArrowRight, Enter, a double-click, or a click on its toggle | expanded (aui-row-group-toggle; “Eng expanded, 3 rows”) |
| group expanded | ArrowLeft, Enter, a double-click, or a click on its toggle | collapsed |
| details collapsed | Enter or ArrowRight in the Details column, or a click on the toggle | expanded (aui-detail-toggle; “Details of Acme expanded”) |
| details expanded | Enter or ArrowLeft in the Details column, or a click on the toggle | collapsed |
| row groups | the group panel’s picker, its pill buttons, or dropping a groupable header on it | regrouped (aui-group-change; “Grouped by Department, City”) |
| editing with ranges | Ctrl+Enter | the value written to every editable cell of the ranges (bulk edit) |
| row mode | any start key on a row’s cell | editors in every editable cell of the row; Tab and Shift+Tab move between them (past the last or first, the row commits and the next or previous row edits); Enter commits the row (one write) after validateRow |
| batch | startBatch(), then writes |
pending values shown (marked and spoken “edited”); commitBatch() applies them (one write, one undo step); cancelBatch() discards them |
| any | Ctrl+Z / Ctrl+Y or Ctrl+Shift+Z | the last write undone / redone (cells focused and selected) |
| cells | Ctrl+V / Ctrl+X / Delete / Ctrl+D / Ctrl+R / fill handle | editable cells written as new row objects in one transaction (aui-cells-change; count announced); with readOnlyEdits only requested |
| expression edited | Enter or Apply with a valid expression | advanced filter applied (aui-filter-change) |
| expression edited | Enter or Apply with a syntax error | error shown with its position, the offending text selected, announced; nothing applied |
| builder closed | Builder | builder open (modal), focus on the root group’s combine choice |
| builder open | Apply / Cancel or Escape | applied / discarded; focus back on Builder |
Accessibility notes
Section titled “Accessibility notes”- One tab stop with roving focus (WAI-ARIA APG Grid). Home/End follow the APG (row), and Tab leaves the grid.
- The focused row and column stay rendered while scrolled away, so virtualization never loses focus.
- Sort changes (“Sorted by Age, descending; City, ascending”), column moves (“Name moved to position 2 of 5”), resizes, group toggles, and loading are announced through the shared polite live region.
- Pinned columns are sticky cells in DOM order, so the reading order matches the visual order in both directions.
- Syntax errors are announced assertively with their position (“Unknown column "Town" at character 16”) and the offending text is selected so it can be retyped at once.
- Filter results are announced politely (“2 rows”); typed values apply after
filterDelayso each keystroke is not announced. Filter state is spoken with the header and shown by a dot on the filter button as well as its color (not color alone). - Pointer resizing needs a drag; Alt+arrows and the state API are the alternatives (WCAG 2.5.7).
- Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”layout: 'fill' fills the host (give the host a height); layout: 'auto' grows with its rows up to the host’s max-block-size. Flex columns share the viewport width and re-flow when it changes. The header stays on top and pinned columns stay at their edges while the grid scrolls in both axes.
Right-to-left
Section titled “Right-to-left”Logical properties: pinned start columns sit on the right in right-to-left layouts, arrow keys and resizing mirror, and the drop indicator follows the visual edge.
Theming
Section titled “Theming”Token-driven. In forced-colors mode, focus outlines and resize lines use Highlight and borders use CanvasText.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { dataGrid: { multiSort: false, overscan: 12 } } });Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All configurable options are dynamic.
Timezones
Section titled “Timezones”datetime columns are formatted in the configured IANA time zone (timezone), never the machine’s zone.
icons.sortAscending (arrow-up), icons.sortDescending (arrow-down), icons.sortNone (arrow-up-down), icons.expand (chevron-right, mirrored in RTL), icons.collapse (chevron-down), icons.loading (spinner), icons.filter (filter), icons.drag (grip, the row drag handle).
Security
Section titled “Security”Cell text uses textContent; render returns text or consumer-owned Nodes; cellClass tokens are validated class names. Filter models from state, URLs, or the UI are validated (DATA_GRID_FILTER) and matched as data; filter values are never parsed as code or HTML. Expressions are read by a hand-written tokenizer and recursive-descent parser (no eval, no Function), with limits on nesting (8 levels) and size (500 conditions). Sizes and offsets are written through the CSSOM, so a strict Content Security Policy with Trusted Types works. No string expressions are evaluated.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. getState() returns JSON the application may store; setState() treats it as untrusted.
Performance
Section titled “Performance”Row offsets come from a Fenwick tree (O(log n) per lookup or height change; uniform heights need no per-row storage); only the visible rows plus overscan and the visible center columns are rendered; rows and cells are reused by id across renders; scroll updates run once per animation frame. Text sorting ranks each column once with the locale collator and then compares numbers, so direction changes and multi-sorts on the same rows are fast. Filters compile once per change; text conditions share one normalized text per row, and the quick filter formats a row’s columns only until one matches, caching the texts per row. Set filter values are extracted once and cached until the rows change. Above about 10 million pixels of content, the scroll space is scaled so very large row counts still scroll smoothly. Budgets: metadata/data-grid/component.json, measured in tests/e2e/perf-data-grid.spec.ts.
Supported data scale
Section titled “Supported data scale”Tested with 1,000,000 rows and 300 columns.
Edge cases
Section titled “Edge cases”- Hosts without a height in
layout: 'fill'collapse to the header; give the host a height or uselayout: 'auto'. rowsare never mutated;setRowskeeps the sort, focus, and scroll position. Transactions never mutate the given rows either; the grid keeps its own row list (read it back withgetStateor keep your own copy).- Change highlighting compares the displayed text, so a value that changes but formats the same (for example a rounding difference) is not highlighted. Highlights are not announced per cell;
aui-rows-changecarries the changed ids for applications that announce. - A column group split by pinning shows one group header per section.
- Hiding the focused column moves the tab stop to the first header.
- Selection is kept by row id across sorting, filtering, paging, and updates; removing selected rows reports them in
aui-selection-change(reason: 'rows'). Select all covers the rows that pass the filters by default (selectAll: 'all'includes filtered-out rows;'page'only the current page). The checkbox column (aui-row-select, a reserved id) is pinned first and is not part of the column state. - Ranges are kept by row and column ids, so they follow sorting and column moves as rectangles of display positions; a range whose corner is filtered out, paged away, or hidden is not shown until it is displayed again. Ranges never include the checkbox column and are not part of the saved state. Ranges always contain the focused cell: moving focus outside them (Tab, a plain arrow key,
focusCell) clears them. - Writes never mutate rows: a writable cell (
editable, plussetValue, or afieldon a plain-object row) gets a new row object (setValue, or a shallow copy with the field replaced) and the changed rows are applied as one transaction (sort, filters, flash, focus, and scroll position stay consistent).setValuemust keep the row id. Read-only cells, the checkbox column, and unchanged values are skipped. - Pasted text is converted with the column’s
parseValue, else by type in the grid’s locale: numbers with the locale’s separators (currency symbols ignored, parentheses negative), dates as ISO or in the locale (numeric or with month names), booleans as the grid’s Yes/No words or true/false, date-times only as ISO instants; empty text writes a blank. Text that does not convert leaves the cell unchanged and is reported. A block that divides the active range evenly is tiled over it; otherwise it is pasted at the range’s top-left cell and rows or columns beyond the grid are dropped. - Editing: a cell is editable when its column is writable (
editableplussetValue, or afieldon plain-object rows). Edits go through the same write path as paste (new row objects, one transaction,aui-cells-changewithsource: 'edit'; withreadOnlyEditsonly requested). The number editor reads the grid’s locale and rejects letters; the date-time editor shows and reads wall-clock time in the grid’s IANA time zone (a time inside a daylight-saving gap is rejected); the select editor’soptionscan be a function of the row. Built-in validation:required, numbermin/max,maxLength, datemin/max(ISO), and values an editor cannot convert; then the column’svalidate. An editor whose row is filtered out or removed is discarded. - Date hierarchies: a date or date-time column with
groupHierarchygroups by each part as its own level (in the grid’s time zone; ISO weeks), labeled “2026”, “Q1 2026”, “January 2026”, “Week 3, 2026”, or the formatted day.showAsshows a numeric aggregate as a percentage of the grand total or of the parent group (top-level groups use the grand total);aggregateFilteredOnly: falseaggregates every row of a group, including rows the filters hide. - Tree data: rows form a tree from paths (
getPath; missing levels become filler rows named by their path element), parent ids (parentIdField; missing parents and cycles make a row a root, reported bygetTreeOrphans(), never looped over), or nested rows (childrenField, read when rows are set; rows added by transactions are roots). The group column shows the tree (labelnames the column that labels rows; paths use their last element);groupByis ignored. A parent with its own row stays a data row: editable, selectable, and copied as usual, with aggregated columns showing the aggregate of the rows below it. Siblings follow the sort; filtering keeps the ancestors of matching rows, andtreeFilter: 'subtree'also keeps the rows below a matching row. On a parent row, ArrowRight, ArrowLeft, Enter, and a double-click expand and collapse in the group column; elsewhere in the row they act as on a data row. - Grouping: groups form over the filtered, sorted rows; groups are ordered by key (by the grouped column’s sort direction when it is sorted; blanks last as “(Blanks)”); rows keep their sort within a group. Aggregates are computed from each group’s rows (an average is never an average of averages; BigInt sums stay BigInt); counts show as plain numbers, other aggregates in the column’s format. Group and total rows are not editable, filled, pasted into, or selected; copy reads their labels and aggregates. Group ids are stable for the same keys, so expansion (in the state) survives updates. Paging pages over the displayed rows (group rows included).
- Row mode (
editMode: 'row'): every editable visible cell of the row gets an editor (large text renders in the cell); the row is outlined; per-cell validation runs first, thenvalidateRow(values, row), whose message (or messages by column) blocks the commit and focuses that cell’s editor. A committed row is one transaction, oneaui-cells-change, and one undo step. - List editors live in a separate entry point so the grid itself does not include Combobox and Multi Select:
comboboxEditor({ values | loadValues, loadDelay, placeholder })edits one value with typeahead filtering or values loaded per query (aborted by newer queries, loading and errors announced);multiSelectEditor({ ..., maxSelected, selectAll })edits an array of values with chips. Choice values are strings, numbers, or booleans;valuescan be a function of the row (dependent lists). The component’s label is the editor’s name (“{column}, {row}”), visually hidden in the cell. Inside the list, Enter chooses an option and Escape closes the list; with the list closed, Enter commits and Escape cancels. - Batch editing: between
startBatch()andcommitBatch(), writes from editing, paste, cut, Delete, and fill become pending values: cells show them in italics with a corner mark and the cell’s name ends with “, edited”; copy reads them; sorting and filtering keep the committed data; events and undo come with the commit (source: 'batch'). Undo during a batch is not available (cancelBatch()discards it). Rows the application replaces or removes during a batch drop their pending values. - Undo: each applied write is one step (
undoLimit, default 20); replacing or updating rows from the application (rows,setRows,applyTransaction) clears the history because old values may be stale; nothing is recorded withreadOnlyEdits. - Fill: two or more numbers or dates continue their linear series (dates by calendar days, or by working days when every source date is a working day of the column’s business calendar); a single value, text, and mixed values repeat; Alt repeats a series or counts up from a single value. Dragging back into the range clears the cells it leaves; double-clicking the handle fills down to the last displayed row. Ctrl+D and Ctrl+R copy (no series).
- Copy uses the displayed text (formatted in the grid’s locale and time zone) or the column’s
copyValue; values with tabs, line breaks, or quotes are quoted. Keyboard copy uses the native copy event (no permission prompt); text the user selected inside a cell copies natively. - Text filters match the displayed text, case- and accent-insensitively by default; incomplete conditions (an operator without a value) filter nothing.
- A set filter lists the distinct displayed values of all rows (not only the filtered ones), blanks first as “(Blanks)”, numbers and dates in value order; the panel renders at most 1,000 matching values and asks for a narrower search. Selecting every value removes the filter.
- The quick filter matches the displayed text of visible searchable columns (or
filterValuewhen given); setsearchable: falseon columns that should not be searched. - Floating filters edit simple filters in place (one condition the compact control can express); other filters show a read-only summary, and Enter on it opens the panel.
- The advanced filter replaces the column filter UI (header buttons and floating row) and the column filters stop applying while it is on; they are kept and apply again when it is turned off. The quick filter and the external filter still apply.
- Advanced expressions: columns by header in brackets (
]]for a]in a header; a column id also works), text and dates in double quotes (\"and\\escape), numbers bare (.decimal separator),andbinds tighter thanor, parentheses group. Keywords are English and case-insensitive. Operators: textcontains,does not contain,=,!=,starts with,ends with; numbers=,!=,<,<=,>,>=,between 1 and 5; dates the same symbols (oron,before,after,on or before,on or after),is today,is this week(and the other relative ranges),is year to date,is in last 7 days,is in next 7 business days,is working day,is holiday; every kindis blank,is not blank; booleansis true,is false; set columnsis any of ("Oslo", blank)(orin (...)). An empty expression clears the filter. - The builder lists at most 1,000 values of a set column (values already chosen stay listed); the expression bar accepts any value.
- The floating number syntax uses
.as the decimal separator:5,>5,>=5,<5,<=5,!=5,5..10.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
DATA_GRID_OPTIONS |
configuration | Missing label, columns, rows, or rowId; malformed column or group; duplicate ids; invalid sizes or option values. Messages name the property, never the value. |
DATA_GRID_ROW_ID |
configuration | Empty or duplicate row id. |
DATA_GRID_STATE |
configuration | Malformed setState input (the grid is left unchanged). |
DATA_GRID_FILTER |
configuration | Malformed filter model in filters, setFilter, advancedFilterModel, setAdvancedFilter, or setState (unknown operator, wrong value type, too many conditions, nesting deeper than 8); the message gives the property path, never the value. |
Syntax errors in the expression bar are not thrown: they are shown, announced, and leave the applied filter unchanged.
Known limitations
Section titled “Known limitations”- Menus: the column menu offers sorting (Clear sort while sorted), the filter, pinning, grouping, hiding, and two submenus: Groups (expand and collapse all, while grouped) and Columns (autosize this or all columns, rename, the column chooser, reset columns); the cell menu offers copying (with or without headers), cutting, pasting (where the Clipboard API is available), pinning the row, and the Groups and Columns submenus. Entries that do not apply are left out, which keeps the menus short enough to show without scrolling. The column chooser (
columnChooser(), opened from Columns > Choose columns or with itsopen()) shows, hides, and reorders columns at once (aui-columns-change); search filters its list.columnMenu({ items(column, defaults) })andcontextMenu({ items(target, defaults) })change the entries: built-in names,'separator', or your own{ id, label, action, disabled, shortcut, icon, items }. Actions taken from a menu behave like their keyboard and pointer counterparts (sorting from the menu emitsaui-sort-change). Outside headers and cells the browser’s menu stays. Accessories attach when the grid is created (the grid must be in the document). - Tooltips: a column’s
tooltip(trueshows the displayed text) for data rows;tooltips({ showDelay, mode: 'truncated', trigger: 'hover' })shows them only for text that does not fit, or only on hover. Find: matches are cells of the displayed rows (all pages; rows of collapsed groups are not searched) whose displayed text contains the text (caseSensitiveoption); the current one is scrolled into view and its page shown; matches follow data changes; the API isfind(text),next(),previous()on the accessory. Notes are stored by your application (notes({ store: { get, set, index }, author }); the grid stores nothing):index()marks the cells that have notes, saves write{ text, author, updated }, an empty note deletes. - Side bar (
sideBar({ panels, position, open, width })): Columns shows the column list (search, Show all, per column visibility, Group toggles for groupable columns, Move up / Move down); Filters shows each filterable column’s filter editor in place (changes apply as in the filter popup). The side bar sits beside the rows (positionstartorend). Pivot rows, columns, and values are edited in the pivot panel. - Status bar (
statusBar({ panels, format })): row counts (“Rows: 120 of 500” while filtered; the server count with a datasource), the selected row count, and while the cell ranges cover two cells or more their count of filled cells and the sum, average, minimum, and maximum of their numbers; panels of your own ({ id, render(context) }) refresh after every change. Toolbar (toolbar({ items, label })): built-ins ('chooser','resetColumns','autoSizeAll','expandAll','collapseAll','separator') and buttons of your own ({ id, label, icon, action }, oritemsfor a menu) next to the search box and the group and pivot panels. - Row spanning (
spanRows) merges adjacent data rows whose displayed values are equal and not blank (or that the function calls equal), at most 500 rows per span; group, total, and full-width rows break spans, and sorting and filtering recompute them. Column spanning (colSpan(row)) covers the next columns of the same pinned section (not withspanRowson the same column). Spans are visual: copies, ranges, and writes still address every cell by its column. - Full-width rows (
fullWidthRow) drawrender(row)across the row; their content stays in view while the rows scroll sideways and is released through the render-release contract when the row leaves; they are never edited, filled, or part of ranges.groupDisplay: 'rows'draws group rows that way (no group column; group totals then name their group in the first data column). Sticky group rows follow the topmost row while grouped (stickyGroupRows: falseturns them off). - Pinned rows: static rows (
pinnedTopRows,pinnedBottomRows) are never sorted, filtered, grouped, selected, or edited; rows pinned by id stay in the body too, follow its filters (a filtered-out row leaves its section), and are read-only in their section.grandTotalworks on flat grids too (labeled “Total” in the first data column), andpinnedTop/pinnedBottomkeep it in a pinned section. Pinned sections stay under the header and at the bottom edge while the body scrolls; rows hidden under them count as off screen when focus moves. - Printing builds a real table (caption,
thwithscope, header rows repeated per page) so printed and saved-as-PDF output keeps its structure; while printing, every other child ofbodyis hidden. Print colors use system colors in a light scheme, whatever the theme. - Formulas live in
@absoluteui/components/data-grid/formulas(our own parser and evaluator; nevereval, so strict CSP and Trusted Types stay intact). Passformulas: formulaEngine({ functions, calendar })and give columns aformulasuch as[Price] * [Quantity]:[Column](column id or header, without case) is the same row’s value, or the whole column inside functions (SUM([Total]));[@Column]is always the same row; A1 references use stable addresses (letters by column definition order, numbers by source row order). Functions: math and aggregates (SUM, AVERAGE, MIN, MAX, COUNT, COUNTA, COUNTBLANK, PRODUCT, ROUND, ROUNDUP, ROUNDDOWN, ABS, INT, MOD, POWER, SQRT, SIGN), conditional (SUMIF, SUMIFS, COUNTIF, COUNTIFS, AVERAGEIF; wildcards * and ?), logic (IF, IFS, IFERROR, IFNA, AND, OR, XOR, NOT, SWITCH, CHOOSE, ISBLANK, ISNUMBER, ISTEXT, ISERROR), text (CONCAT, TEXTJOIN, LEFT, RIGHT, MID, LEN, UPPER, LOWER, PROPER, TRIM, FIND, SEARCH, SUBSTITUTE, REPT, VALUE, TEXT), dates (TODAY in the grid time zone, DATE, YEAR, MONTH, DAY, WEEKDAY, DAYS, EDATE, EOMONTH, NETWORKDAYS and WORKDAY on the engine’s business calendar), lookups (XLOOKUP, INDEX, MATCH, VLOOKUP). Formulas use.for decimals and,between arguments whatever the locale. Calculated columns are read-only, sort, filter, group, aggregate, and export their results (CSV and Excel write values). Results recalculate when rows change; cycles give#CIRCULAR!; limits (8192 characters, 64 nesting levels, 1,000,000 cells per range, 1,000,000 evaluation steps) give errors, never hangs. Error cells show the code and read its meaning (“#DIV/0!, division by zero”). Columns withformulas: truehold cell formulas in the row data (a value that is text starting with=): the cell shows the result, the editor shows the formula (a text editor; other input is read as the column type), invalid formulas are refused with the position of the problem, and fill, Ctrl+D / Ctrl+R, and pasting cells copied in the grid move relative A1 references ($parts stay); text pasted from elsewhere is kept as typed. The editor of a formulas cell is a combobox: typing a function name or[lists matching functions and columns (ArrowUp and ArrowDown move, Enter or Tab accepts, Escape closes the list), the signature of the function around the caret shows under the field and is part of its description, a syntax problem shows there after a pause, and while a formula is edited a click on another cell inserts its address where an operand is expected (keyboard users type references, helped by the suggestions). TheformulaBar()accessory (fromdata-grid/formulas) shows the focused cell’s address and formula above the grid (read-only). - Charts live in
@absoluteui/components/data-grid/charts(outside the core bundle, drawn by AbsoluteUI chart components). Sparklines in cells: spreadsparklineColumn({ values, label, variant, color, min, max, valueFormat, sortBy, locale })into a column; each cell draws a Sparkline named “{label}: {count} values, from {first} to {last}, …”, copy and exports get the numbers as text, and sorting compares the last value (orsum,min,max). Load the Sparkline styles. Class:aui-data-grid__sparkline. Range charts:chartRange(grid, { type, seriesBy, title, range })opens a panel docked below the grid (a region named “Chart of {title}”, resizable, Escape or Close closes it and focus returns to the grid) with a bar, stacked bar, line, area, or pie chart of the selected cells (the first text column names the categories; numeric columns, or rows withseriesBy: 'rows', are the series); it follows edits, transactions, sorting, and filtering, and each chart has its own data table.chartPivot(grid, { type, title, level })does the same for pivot results (the rows of a group level against the value columns). Both return{ element, update, close }; load the Bar, Line, and Pie Chart styles. Classes:aui-data-grid-chart,__tools,__field,__close,__body,__chart,__empty. To offer it in the cell menu, add an item:contextMenu({ items: (target, defaults) => [...defaults, { id: 'chart', label: 'Chart range', action: () => chartRange(grid) }] }). - For tools (for example an AI assistant),
@absoluteui/components/data-grid/schemahasdataGridStateSchema(grid)(a JSON Schema, draft 2020-12, of the view statesetStateaccepts, with the grid’s column ids, filter kinds, groups, and pivot aggregates),describeState(grid)(a short English summary of the current view), andapplyState(grid, state)({ ok: true }or{ ok: false, error }with the validation message, so a tool can correct its proposal). Only view state: no row data, no edits, no row ids;setStatevalidates everything a tool proposes. - PDF export lives in
@absoluteui/components/data-grid/pdf:toPdf(grid, options)returns a Promise of a PDF Blob with thetoCsvrow and column choices, the title on the first page, column group and header rows repeated on every page, bold group and total rows, end-aligned numbers, and “Page n of N” (pageLabel); optionspageSize(a4,letter),orientation(default landscape),margin,fontSize,rightToLeft,columnGroups. Column widths follow the grid, scaled down to fit the page; long text is cut with an ellipsis. Latin text (Windows-1252) uses the standard Helvetica fonts; for other scripts passfonts: { regular, bold }with TrueType or OpenType bytes (embedded whole, with a ToUnicode map so text can be copied and searched; fonts whose license forbids embedding are refused; font collections are not read). Right-to-left grids mirror the columns and order bidirectional text in a simplified way; Arabic letters are not shaped, so use the browser’s Save as PDF throughprint()for Arabic and other complex scripts. The PDF is not tagged (no PDF/UA structure): for assistive technology prefer the grid, CSV, or Excel. More than 100,000 rows throws. The cell menu offers PDF withcontextMenu({ export: { pdf: (g) => toPdf(g) } }). - Excel export lives in
@absoluteui/components/data-grid/export(outside the core bundle):toXlsx(grid, options)returns a Promise of an .xlsx Blob;xlsxSheet(grid, options)andwriteXlsx({ sheets })build workbooks with several sheets (grids or plain rows). Options: thetoCsvrow and column choices,sheetName,header,columnGroups(merged),styles(named styles forexcel.styleandexcel.cellStyle),headerStyle,groupStyle,totalStyle,freeze(header rows and start-pinned columns, default on),outline(group and tree levels, collapsed like the grid, default on),autoFilter,dateFormat,dateTimeFormat(in the grid time zone),protection(password,spinCount,allow),rightToLeft,title,creator. Values are typed (numbers, booleans, dates as Excel dates); text is always written as text, so formula-like values cannot run; formulas come only fromexcel.formulacode. Links keep http, https, and mailto only; images must be PNG or JPEG bytes. A protection password is hashed with SHA-512, a random salt, andspinCountrounds (default 100000, which takes a few seconds); it is never stored. Excel limits apply: 1,048,576 rows, 16,384 columns, 32,767 characters per cell (longer text is cut). Passexport: { excel: (g) => toXlsx(g) }tocontextMenufor the cell menu’s Excel item. - CSV export escapes formula-like text (=, +, -, @, tab, carriage return) with a leading quote, including group labels when the
indentstarts with one of them; numbers the grid formats itself are not escaped,valuecallbacks returning strings are. The cell menu (contextMenu accessory) has Export > CSV (and Excel withexport: { excel }), named after the grid’s label;export: falseremoves it. - State:
getState()includesdetails,pinnedRows,pivot, andcolumns.headers;setStaterestores them (a malformed pivot throwsDATA_GRID_STATEbefore anything changes; unknown pinned ids are dropped). Aligned grids share column state by column id: columns only one grid has are left as they are. - Auto-generated columns:
inferColumns(rows, { sample, exclude })returns columns for the rows’ own keys (number, boolean, date for PlainDate, datetime for Instant or ZonedDateTime, else text; keys holding only objects are left out). For a dropped CSV file:parseCsv(text, { header: true })from@absoluteui/helpers/csv, thencoerceCsvValues(rows)(numbers and true/false become typed; numbers with leading zeros stay text), theninferColumns. - Managed row dragging moves client rows in source order only: flat rows that are not sorted, filtered, grouped, or pivoted, or tree data with
parentIdField(moves keep row objects and copy a moved row with its new parent id). Otherwise, and withoutmanaged, the grid only emitsaui-row-drop. A move is one undo step;moveRowclears the undo history. Rows dropped from another grid are added with a transaction (it clears the undo history), only to client rows. WithnativeDatathe browser draws the drag and pointer edge cases follow native drag and drop (no touch drag where the browser has none; the menu still works). - Row numbers count displayed rows (sorting, filtering, grouping, and paging renumber them); with cell ranges a click on a number selects the row’s cells; numbers are never copied, pasted into, or filled. Row heights set by the user or
setRowHeightstay with the row id (not withautoRowHeight, where the resizer is off). - Server row model (
datasource):getRows({ start, end, sort, filters, quickFilter, advancedFilter }, signal)returns{ rows, rowCount? }; blocks ofblockSizerows load as they scroll into view (the topmost first,maxConcurrentLoadsat a time, debounced byblockLoadDelay; stale requests are aborted). WithoutrowCountthe total grows a block at a time until a block comes back short. A sort, filter, quick filter, or advanced filter change purges the cache and reloads from the top (the previous count stays as an estimate). Failed blocks are never retried automatically (retryLoads(), or Retry).maxBlocksreleases the least recently used blocks.applyTransactionupdates loaded rows;applyServerTransactionalso adds and removes loaded rows (later rows shift; blocks left incomplete load again when shown). Edits, paste, fill, and undo write loaded rows. Selection keeps the ids of rows that are not loaded; the header checkbox selects every row, loaded or not (getServerSelection()returns{ selectAll: true, toggled }, toggled being the exceptions), andgetSelected()lists loaded rows only. Server groups: withgroupBythe request carriesgroupByandgroupKeys; the top level returns group rows (ordinary rows: the key is read from the grouped column, aggregates from aggregated columns, the count fromgetChildCount(row)), and each expanded group loads its own rows (blocks, loading and failed rows, and paging as at the top level) withgroupKeysset to its path; loading rows of a group are sized by its count. Collapsed groups keep their rows unlesspurgeClosedGroups. Server tree data:treeData: { serverGroup(row), serverKey(row), label }; a parent’s children load withgroupKeysholding the keys of its ancestors and itself.expandAll()expands the loaded groups; group rows have no group checkbox (their rows are not all loaded). Not combinable:pivot,detail, and client tree modes (rejected). Set filters listfilterValues, else the values of loaded rows. - Pivot mode: rows group by the row fields (sorted by key like groups; the last level has no data rows), and the Pivot Grid engine aggregates the rows that pass the filters for every (row, column) key pair: a column group per column key (nested per column field, labeled like the column) holds a result column per value (“Sum of Salary”), then “Total” columns. Sums, averages, minimums, and maximums read numbers (currency columns keep their currency); counts count non-blank values and distinct counts compare values (dates by day). The data columns hide while pivoting; generated columns are not sortable or movable. Without row fields one row shows the grand totals;
grandTotaladds a total row otherwise. More thanpivotMaxColumnsresult columns are left out (announced;getPivotTruncation()).treeDatatakes precedence overpivot, andpivotovergroupBy. - Master/detail: detail rows follow their master rows (paging counts master rows only; a page change keeps them with their masters), are not selectable, editable, or part of copies, and do not scroll sideways. Content renders once and is kept while expanded, and for up to
keepcollapsed details (oldest released first, throughdestroy); a replaced row object renders it again. Heights are fixed (default 300) or measured (auto). - Not available yet: sorting pivot rows by a result column, and pivot mode over a datasource.
- Column filter changes apply live; there is no Apply button mode yet.
- Advanced filter keywords (
and,contains,is any of, …) are English; column headers and messages are localized. - Children stay within their column group when moved.
- Pointer resizing needs a drag; keyboard and API alternatives exist.
- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML strings in cells.
- String expressions (only functions).