Data grid

A data grid presents rows of records that readers sort, select, and move through by keyboard, such as an order list of thousands. Its navigation mode sets whether the arrow keys step between cells or whole rows, and it stays fast on thousands of rows. The grids below are live, each on its own theme.

Reference docs⁠

BlazorReactWebOverviewExamplesAPIStylingAccessibility

Choosing a way to show a collection⁠

Three components show many items at once. Each suits a different job:

  • List: a column of items to scan and act on, such as contacts or settings.
  • Data table: read-only rows and columns to compare, such as an invoice or a price table.
  • Data grid: many rows the reader sorts, selects, and moves through by keyboard, such as an order list of thousands.

One job belongs elsewhere. Splitting a long collection into pages is a paginator, used alongside any of these.

Choosing a variant⁠

Four variants set how much a data grid stands out from the page, from most to least:

  • Filled: a grid that is the main content of a page, such as a dashboard's order list, on the primary container color.
  • Tonal: a grid that shares a screen with a filled element, on the secondary container color.
  • Surface: a grid that needs its own ground, such as an admin list in a panel of another color, on the lowest surface container color.
  • Standard: the default, with no fill, for a grid that sits directly on the page or inside a card and takes that container's color.

Built in⁠

  • navigation-mode gives the grid one tab stop, then arrow keys that move between cells or between rows.
  • A column with sortable sorts on a click or on Enter, cycles none, ascending, and descending, and announces the result.
  • selectable selects one cell or row at a time and fires an event for each selection and deselection.
  • virtualize keeps a list of thousands of rows light.
  • unique-identifier keeps your place in a long list, so a sort or refresh does not send the reader back to the top.
  • Loads and errors are announced to a screen reader without any markup of your own.

Using data grids well⁠

  • Keep column titles short, and give numeric columns a numeric type so their values line up on the right.
  • Give a currency column its currency code, such as "currency": "EUR". The grid's locale decides how a price is written, not which currency it is in, and a column with no code shows plain numbers.
  • Design for one selected row or cell at a time; the grid has no checkbox column or select-all header.
  • Put paging controls in a footer with a rows-per-page choice and a position readout such as "1–10 of 100", using a paginator that slices the data you pass in.
  • Clear or reapply the selection when the page changes, because it points at an index and not at a record.

These rules follow Material 3 Expressive's guidance for data tables, on material.io.

Variants⁠

variant sets how much the grid stands out: filled, tonal, surface, or standard. Omit it and the grid takes the variant from your style configuration, which is standard unless you have changed it. The overview says when to choose each.

Caption position⁠

A child in the default slot is the grid's caption and names it for screen readers. caption-position places it before the rows (leading) or after them (trailing). Omit it and the caption takes the position from your style configuration, which is leading unless you have changed it.

Density⁠

density runs from 0 to 4. Higher values draw shorter rows, from 52 pixels at 0 to 36 pixels at 4, so a screen holds more records. Omit it and the grid takes the density from your style configuration, which is 0 unless you have changed it.

Rows and borders⁠

striped shades alternate rows, show-column-dividers draws a line between columns, and borderless removes the outer frame while the row and column dividers stay. Turn each on to see the change.

navigation-mode decides what the arrow keys move between. In cell mode, the default, every cell is a stop and the arrows move in four directions. In row mode, the arrows move between whole rows only. The Accessibility tab lists every key. Click a grid, then use the arrow keys.

Selection⁠

Set selectable and a click, Enter, or Space selects the focused cell, or the row in row mode. Selection is single: choosing another deselects the first, and choosing the selected one deselects it. Each change fires cell-select, cell-deselect, row-select, or row-deselect, and the demo reports the last one.

Data and columns⁠

items holds the rows as an array of objects, and columns lists a field, title, and options for each column. With no columns, the grid builds them from the first row's keys. unique-identifier names the field that identifies a row, and the grid needs it: without it, keyboard focus is dropped after every sort or refresh instead of returning to the same record. grid-label names the grid for screen readers when there is no caption.

Sorting⁠

A column with sortable sorts when its header is activated, cycling none, ascending, descending, and none. One column sorts at a time, the input array is never changed, and each change fires sort-change. Code can call sort() and read sortDescriptors. A sort clears the selection.

Large data sets⁠

Set virtualize and the grid draws only the rows in view, which needs one constant row height. overscan-count is how many extra rows it fetches beyond the visible area, 3 by default, and a small value avoids over-fetching. For server-side sorting or paging, set itemsProvider to an async function that asks for rows and returns the rows with a total count. A function cannot be written in a demo, and a short list shows no difference, so the demo below only sets the switch.

Properties⁠

PropertyAttributeTypeDescription
borderlessborderlessbooleandefault falseRemoves the outer frame, including the header's underline. Row and cell dividers stay visible. See Rows and borders.
captionPositioncaption-positionleading, trailingCaptionPositionCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configurationThe caption's position in relation to the component. See Caption position.
columnsColumnDefinition[]default []Column definitions. If not provided, columns will be auto-generated from data (if possible). See Data and columns.
densitydensity0, 1, 2, 3, 4DensityDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configurationHow tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density.
gridLabelgrid-labelstringThe name a screen reader announces for the component. See Data and columns.
itemsTItem[]default []Data source as an array of objects. Use this for client-side data. See Data and columns.
itemsProviderGridItemsProvider<TItem>Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets.
localelocalestringThe BCP 47 locale, such as de-DE, the component writes numbers and dates in, and translates its built-in screen-reader text into where it has a translation. Empty means the application's configured locale (AppConfiguration.locale), or the browser's preferred language when it sets none.
navigationModenavigation-modecell, rowGridNavigationModeGridNavigationMode.Cell, .Rowdefault GridNavigationMode.CellSets how the arrow keys move focus: cell by cell in all four directions, or row by row up and down. It works independently of selectable. See Navigation mode.
overscanCountoverscan-countnumberdefault 3How many rows beyond the visible ones are fetched ahead of scrolling. Keep it small to avoid over-fetching from the server. See Large data sets.
selectableselectablebooleandefault falseWhether selection is enabled. When true, cells or rows (depending on navigationMode) can be selected by click or Enter/Space, and a screen reader announces the selection. See Selection.
showColumnDividersshow-column-dividersbooleandefault falseShows vertical dividers between columns, which helps tell columns apart when there are many. See Rows and borders.
sortDescriptorsread-onlySortDescriptor[]The current sort, ordered by precedence, or an empty array when unsorted. Changing the returned array does not change the sort. See Sorting.
stripedstripedbooleandefault falseShades alternate rows. See Rows and borders.
uniqueIdentifierunique-identifierstringThe name of a field whose value identifies a row. Required: without it, the grid cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Data and columns.
variantvariantfilled, standard, surface, tonalTableVariantTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configurationThe component's color scheme. filled uses the primary container color for high emphasis, tonal the secondary container color for medium emphasis, surface the lowest surface container color, and standard no fill, taking the color of whatever the table sits on. Unset, it comes from the style configuration's defaultTableVariant, which ships as standard. See Variants.
virtualizevirtualizebooleandefault falseShows only the rows in view, for large datasets. Every row must be the same height. See Large data sets.

Slots⁠

SlotDescription
(default)Default slot for caption content. Caption position controlled by captionPosition property.

Events⁠

EventTypeDetailDescription
cell-selectCellSelectEventCellSelectEventDetail<TItem>Dispatched when a cell becomes selected (cell navigation mode, selectable = true). It bubbles and is composed.
cell-deselectCellDeselectEventCellDeselectEventDetail<TItem>Dispatched when a cell becomes deselected (cell navigation mode, selectable = true). It bubbles and is composed.
row-selectRowSelectEventRowSelectEventDetail<TItem>Dispatched when a row becomes selected (row navigation mode, selectable = true). It bubbles and is composed.
row-deselectRowDeselectEventRowDeselectEventDetail<TItem>Dispatched when a row becomes deselected (row navigation mode, selectable = true). It bubbles and is composed.
sort-changeSortChangeEventSortChangeEventDetailDispatched when the sort state changes (a sortable column header is activated or sort() is called). It bubbles and is composed.
cell-activateCellActivateEventCellActivateEventDetail<TItem>Dispatched when a control rendered by ColumnDefinition.actionLabel/actionHref is activated — by pointer, Enter, or Space. It bubbles and is composed.

A sort clears the selection and fires the matching deselect event. Selection is by position, so new items leave it pointing at whichever record now sits at that index.

The column options that raise cell-activate are provisional and carry no compatibility promise.

Methods⁠

MethodReturnsDescription
sort(field: string, direction?: string)voidProgrammatically sorts by a column field. direction omitted = cycle from the column's current state exactly as a user activation would. No-op (with a console warning) if the field is unknown or the column is not sortable. Fires sort-change like a user activation.

Props⁠

PropTypeDescription
borderlessbooleandefault falseRemoves the outer frame, including the header's underline. Row and cell dividers stay visible. See Rows and borders.
captionPositionCaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configurationThe caption's position in relation to the component. See Caption position.
columnsColumnDefinition[]default []Column definitions. If not provided, columns will be auto-generated from data (if possible). See Data and columns.
densityDensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configurationHow tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density.
gridLabelstringThe name a screen reader announces for the component. See Data and columns.
itemsTItem[]default []Data source as an array of objects. Use this for client-side data. See Data and columns.
itemsProviderGridItemsProvider<TItem>Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets.
localestringThe BCP 47 locale, such as de-DE, the component writes numbers and dates in, and translates its built-in screen-reader text into where it has a translation. Empty means the application's configured locale (AppConfiguration.locale), or the browser's preferred language when it sets none.
navigationModeGridNavigationModeTypeGridNavigationMode.Cell, .Rowdefault GridNavigationMode.CellSets how the arrow keys move focus: cell by cell in all four directions, or row by row up and down. It works independently of selectable. See Navigation mode.
overscanCountnumberdefault 3How many rows beyond the visible ones are fetched ahead of scrolling. Keep it small to avoid over-fetching from the server. See Large data sets.
selectablebooleandefault falseWhether selection is enabled. When true, cells or rows (depending on navigationMode) can be selected by click or Enter/Space, and a screen reader announces the selection. See Selection.
showColumnDividersbooleandefault falseShows vertical dividers between columns, which helps tell columns apart when there are many. See Rows and borders.
sortDescriptorsread-only (ref)SortDescriptor[]The current sort, ordered by precedence, or an empty array when unsorted. Changing the returned array does not change the sort. See Sorting.
stripedbooleandefault falseShades alternate rows. See Rows and borders.
uniqueIdentifierstringThe name of a field whose value identifies a row. Required: without it, the grid cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Data and columns.
variantTableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configurationThe component's color scheme. filled uses the primary container color for high emphasis, tonal the secondary container color for medium emphasis, surface the lowest surface container color, and standard no fill, taking the color of whatever the table sits on. Unset, it comes from the style configuration's defaultTableVariant, which ships as standard. See Variants.
virtualizebooleandefault falseShows only the rows in view, for large datasets. Every row must be the same height. See Large data sets.

Children⁠

ChildDescription
childrenDefault slot for caption content. Caption position controlled by captionPosition prop.

Events⁠

PropArgumentDescription
onCellSelectCellSelectEvent<TItem>Dispatched when a cell becomes selected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
onCellDeselectCellDeselectEvent<TItem>Dispatched when a cell becomes deselected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
onRowSelectRowSelectEvent<TItem>Dispatched when a row becomes selected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
onRowDeselectRowDeselectEvent<TItem>Dispatched when a row becomes deselected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
onSortChangeSortChangeEventDispatched when the sort state changes (a sortable column header is activated or sort() is called). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors.
onCellActivateCellActivateEvent<TItem>Dispatched when a control rendered by ColumnDefinition.actionLabel/actionHref is activated — by pointer, Enter, or Space. It bubbles and is composed. Its detail carries item, rowIndex, field, columnIndex, value, and originalEvent.

A sort clears the selection and fires the matching deselect event. Selection is by position, so new items leave it pointing at whichever record now sits at that index.

The column options that raise cell-activate are provisional and carry no compatibility promise.

Methods⁠

Call these on the element the ref holds.

MethodReturnsDescription
sort(field: string, direction?: string)voidProgrammatically sorts by a column field. direction omitted = cycle from the column's current state exactly as a user activation would. No-op (with a console warning) if the field is unknown or the column is not sortable. Fires sort-change like a user activation.

Parameters⁠

ParameterTypeDescription
Borderlessbool?default falseRemoves the outer frame, including the header's underline. Row and cell dividers stay visible. See Rows and borders.
CaptionPositionCaptionPosition?CaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configurationThe caption's position in relation to the component. See Caption position.
ColumnsIEnumerable<ColumnDefinition>?default []Column definitions. If not provided, columns will be auto-generated from data (if possible). See Data and columns.
DensityDensity?Density.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configurationHow tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density.
GridLabelstring?The name a screen reader announces for the component. See Data and columns.
ItemsIEnumerable<TItem>?default []Data source as an array of objects. Use this for client-side data. See Data and columns.
ItemsProviderGridItemsProvider<TItem>?Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while Items has rows. See Large data sets.
Localestring?The BCP 47 locale, such as de-DE, the component writes numbers and dates in, and translates its built-in screen-reader text into where it has a translation. Empty means the application's configured locale (AppConfiguration.locale), or the browser's preferred language when it sets none.
NavigationModeGridNavigationMode?GridNavigationMode.Cell, .Rowdefault GridNavigationMode.CellSets how the arrow keys move focus: cell by cell in all four directions, or row by row up and down. It works independently of Selectable. See Navigation mode.
OverscanCountint?default 3How many rows beyond the visible ones are fetched ahead of scrolling. Keep it small to avoid over-fetching from the server. See Large data sets.
Selectablebool?default falseWhether selection is enabled. When true, cells or rows (depending on NavigationMode) can be selected by click or Enter/Space, and a screen reader announces the selection. See Selection.
ShowColumnDividersbool?default falseShows vertical dividers between columns, which helps tell columns apart when there are many. See Rows and borders.
Stripedbool?default falseShades alternate rows. See Rows and borders.
UniqueIdentifierstring?The name of a field whose value identifies a row. Required: without it, the grid cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Data and columns.
VariantTableVariant?TableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configurationThe component's color scheme. filled uses the primary container color for high emphasis, tonal the secondary container color for medium emphasis, surface the lowest surface container color, and standard no fill, taking the color of whatever the table sits on. Unset, it comes from the style configuration's defaultTableVariant, which ships as standard. See Variants.
Virtualizebool?default falseShows only the rows in view, for large datasets. Every row must be the same height. See Large data sets.

Render fragments⁠

ParameterTypeDescription
ChildContentRenderFragment?Default slot for caption content. Caption position controlled by CaptionPosition parameter.

Event callbacks⁠

ParameterTypeDescription
OnCellSelectEventCallback<CellSelectEventArgs<TItem>>Dispatched when a cell becomes selected (cell navigation mode, Selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
OnCellDeselectEventCallback<CellDeselectEventArgs<TItem>>Dispatched when a cell becomes deselected (cell navigation mode, Selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
OnRowSelectEventCallback<RowSelectEventArgs<TItem>>Dispatched when a row becomes selected (row navigation mode, Selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
OnRowDeselectEventCallback<RowDeselectEventArgs<TItem>>Dispatched when a row becomes deselected (row navigation mode, Selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
OnSortChangeEventCallback<SortChangeEventArgs>Dispatched when the sort state changes (a sortable column header is activated or sort() is called). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors.
OnCellActivateEventCallback<CellActivateEventArgs<TItem>>Dispatched when a control rendered by ColumnDefinition.actionLabel/actionHref is activated — by pointer, Enter, or Space. It bubbles and is composed. Its detail carries item, rowIndex, field, columnIndex, value, and originalEvent.

A sort clears the selection and fires the matching deselect event. Selection is by position, so new items leave it pointing at whichever record now sits at that index.

The column options that raise cell-activate are provisional and carry no compatibility promise.

Inputs⁠

InputTypeDescription
borderlessbooleandefault falseRemoves the outer frame, including the header's underline. Row and cell dividers stay visible. See Rows and borders.
captionPositionCaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configurationThe caption's position in relation to the component. See Caption position.
columnsColumnDefinition[]default []Column definitions. If not provided, columns will be auto-generated from data (if possible). See Data and columns.
densityDensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configurationHow tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density.
gridLabelstringThe name a screen reader announces for the component. See Data and columns.
itemsTItem[]default []Data source as an array of objects. Use this for client-side data. See Data and columns.
itemsProviderGridItemsProvider<TItem>Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets.
localestringThe BCP 47 locale, such as de-DE, the component writes numbers and dates in, and translates its built-in screen-reader text into where it has a translation. Empty means the application's configured locale (AppConfiguration.locale), or the browser's preferred language when it sets none.
navigationModeGridNavigationModeTypeGridNavigationMode.Cell, .Rowdefault GridNavigationMode.CellSets how the arrow keys move focus: cell by cell in all four directions, or row by row up and down. It works independently of selectable. See Navigation mode.
overscanCountnumberdefault 3How many rows beyond the visible ones are fetched ahead of scrolling. Keep it small to avoid over-fetching from the server. See Large data sets.
selectablebooleandefault falseWhether selection is enabled. When true, cells or rows (depending on navigationMode) can be selected by click or Enter/Space, and a screen reader announces the selection. See Selection.
showColumnDividersbooleandefault falseShows vertical dividers between columns, which helps tell columns apart when there are many. See Rows and borders.
stripedbooleandefault falseShades alternate rows. See Rows and borders.
uniqueIdentifierstringThe name of a field whose value identifies a row. Required: without it, the grid cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Data and columns.
variantTableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configurationThe component's color scheme. filled uses the primary container color for high emphasis, tonal the secondary container color for medium emphasis, surface the lowest surface container color, and standard no fill, taking the color of whatever the table sits on. Unset, it comes from the style configuration's defaultTableVariant, which ships as standard. See Variants.
virtualizebooleandefault falseShows only the rows in view, for large datasets. Every row must be the same height. See Large data sets.

Content projection⁠

ContentDescription
content with no slotDefault slot for caption content. Caption position controlled by captionPosition input.

Outputs⁠

OutputEventDescription
cwCellSelectCellSelectEventDispatched when a cell becomes selected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
cwCellDeselectCellDeselectEventDispatched when a cell becomes deselected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
cwRowSelectRowSelectEventDispatched when a row becomes selected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
cwRowDeselectRowDeselectEventDispatched when a row becomes deselected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
cwSortChangeSortChangeEventDispatched when the sort state changes (a sortable column header is activated or sort() is called). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors.
cwCellActivateCellActivateEventDispatched when a control rendered by ColumnDefinition.actionLabel/actionHref is activated — by pointer, Enter, or Space. It bubbles and is composed. Its detail carries item, rowIndex, field, columnIndex, value, and originalEvent.

A sort clears the selection and fires the matching deselect event. Selection is by position, so new items leave it pointing at whichever record now sits at that index.

The column options that raise cell-activate are provisional and carry no compatibility promise.

Props⁠

PropTypeDescription
borderlessbooleandefault falseRemoves the outer frame, including the header's underline. Row and cell dividers stay visible. See Rows and borders.
captionPositionCaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configurationThe caption's position in relation to the component. See Caption position.
columnsColumnDefinition[]default []Column definitions. If not provided, columns will be auto-generated from data (if possible). See Data and columns.
densityDensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configurationHow tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density.
gridLabelstringThe name a screen reader announces for the component. See Data and columns.
itemsTItem[]default []Data source as an array of objects. Use this for client-side data. See Data and columns.
itemsProviderGridItemsProvider<TItem>Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets.
localestringThe BCP 47 locale, such as de-DE, the component writes numbers and dates in, and translates its built-in screen-reader text into where it has a translation. Empty means the application's configured locale (AppConfiguration.locale), or the browser's preferred language when it sets none.
navigationModeGridNavigationModeTypeGridNavigationMode.Cell, .Rowdefault GridNavigationMode.CellSets how the arrow keys move focus: cell by cell in all four directions, or row by row up and down. It works independently of selectable. See Navigation mode.
overscanCountnumberdefault 3How many rows beyond the visible ones are fetched ahead of scrolling. Keep it small to avoid over-fetching from the server. See Large data sets.
selectablebooleandefault falseWhether selection is enabled. When true, cells or rows (depending on navigationMode) can be selected by click or Enter/Space, and a screen reader announces the selection. See Selection.
showColumnDividersbooleandefault falseShows vertical dividers between columns, which helps tell columns apart when there are many. See Rows and borders.
stripedbooleandefault falseShades alternate rows. See Rows and borders.
uniqueIdentifierstringThe name of a field whose value identifies a row. Required: without it, the grid cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Data and columns.
variantTableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configurationThe component's color scheme. filled uses the primary container color for high emphasis, tonal the secondary container color for medium emphasis, surface the lowest surface container color, and standard no fill, taking the color of whatever the table sits on. Unset, it comes from the style configuration's defaultTableVariant, which ships as standard. See Variants.
virtualizebooleandefault falseShows only the rows in view, for large datasets. Every row must be the same height. See Large data sets.

Slots⁠

SlotDescription
defaultDefault slot for caption content. Caption position controlled by captionPosition prop.

Events⁠

EventTypeDescription
cellSelectCellSelectEventDispatched when a cell becomes selected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
cellDeselectCellDeselectEventDispatched when a cell becomes deselected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
rowSelectRowSelectEventDispatched when a row becomes selected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
rowDeselectRowDeselectEventDispatched when a row becomes deselected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
sortChangeSortChangeEventDispatched when the sort state changes (a sortable column header is activated or sort() is called). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors.
cellActivateCellActivateEventDispatched when a control rendered by ColumnDefinition.actionLabel/actionHref is activated — by pointer, Enter, or Space. It bubbles and is composed. Its detail carries item, rowIndex, field, columnIndex, value, and originalEvent.

A sort clears the selection and fires the matching deselect event. Selection is by position, so new items leave it pointing at whichever record now sits at that index.

The column options that raise cell-activate are provisional and carry no compatibility promise.

Props⁠

PropTypeDescription
borderlessbooleandefault falseRemoves the outer frame, including the header's underline. Row and cell dividers stay visible. See Rows and borders.
captionPositionCaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configurationThe caption's position in relation to the component. See Caption position.
columnsColumnDefinition[]default []Column definitions. If not provided, columns will be auto-generated from data (if possible). See Data and columns.
densityDensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configurationHow tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density.
gridLabelstringThe name a screen reader announces for the component. See Data and columns.
itemsTItem[]default []Data source as an array of objects. Use this for client-side data. See Data and columns.
itemsProviderGridItemsProvider<TItem>Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets.
localestringThe BCP 47 locale, such as de-DE, the component writes numbers and dates in, and translates its built-in screen-reader text into where it has a translation. Empty means the application's configured locale (AppConfiguration.locale), or the browser's preferred language when it sets none.
navigationModeGridNavigationModeTypeGridNavigationMode.Cell, .Rowdefault GridNavigationMode.CellSets how the arrow keys move focus: cell by cell in all four directions, or row by row up and down. It works independently of selectable. See Navigation mode.
overscanCountnumberdefault 3How many rows beyond the visible ones are fetched ahead of scrolling. Keep it small to avoid over-fetching from the server. See Large data sets.
selectablebooleandefault falseWhether selection is enabled. When true, cells or rows (depending on navigationMode) can be selected by click or Enter/Space, and a screen reader announces the selection. See Selection.
showColumnDividersbooleandefault falseShows vertical dividers between columns, which helps tell columns apart when there are many. See Rows and borders.
stripedbooleandefault falseShades alternate rows. See Rows and borders.
uniqueIdentifierstringThe name of a field whose value identifies a row. Required: without it, the grid cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Data and columns.
variantTableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configurationThe component's color scheme. filled uses the primary container color for high emphasis, tonal the secondary container color for medium emphasis, surface the lowest surface container color, and standard no fill, taking the color of whatever the table sits on. Unset, it comes from the style configuration's defaultTableVariant, which ships as standard. See Variants.
virtualizebooleandefault falseShows only the rows in view, for large datasets. Every row must be the same height. See Large data sets.

Snippets⁠

SnippetDescription
childrenDefault slot for caption content. Caption position controlled by captionPosition prop.

Events⁠

PropTypeDescription
onCellSelectCellSelectEventDispatched when a cell becomes selected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
onCellDeselectCellDeselectEventDispatched when a cell becomes deselected (cell navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, field, value, columnIndex, rowIndex, and originalEvent.
onRowSelectRowSelectEventDispatched when a row becomes selected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
onRowDeselectRowDeselectEventDispatched when a row becomes deselected (row navigation mode, selectable = true). It bubbles and is composed. Its detail carries item, rowIndex, and originalEvent.
onSortChangeSortChangeEventDispatched when the sort state changes (a sortable column header is activated or sort() is called). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors.
onCellActivateCellActivateEventDispatched when a control rendered by ColumnDefinition.actionLabel/actionHref is activated — by pointer, Enter, or Space. It bubbles and is composed. Its detail carries item, rowIndex, field, columnIndex, value, and originalEvent.

A sort clears the selection and fires the matching deselect event. Selection is by position, so new items leave it pointing at whichever record now sits at that index.

The column options that raise cell-activate are provisional and carry no compatibility promise.

Each attribute value has its own tokens; a cell shows its token's value, and selecting the cell shows the token's fallback path, with each name and value ready to copy. For example, the standard column's error-color row is --ct-table-standard-error-color, which defaults to --ct-sys-color-error.

Variant⁠

Namestandardsurfacefilledtonal
error-color--ct-sys-color-error --ct-table-standard-error-color--ct-sys-color-error --ct-table-surface-error-color--ct-sys-color-error --ct-table-filled-error-color--ct-sys-color-error --ct-table-tonal-error-color
error-container-color--ct-sys-color-error-container --ct-table-standard-error-container-color--ct-sys-color-error-container --ct-table-surface-error-container-color--ct-sys-color-error-container --ct-table-filled-error-container-color--ct-sys-color-error-container --ct-table-tonal-error-container-color
header-container-colortransparent --ct-table-standard-header-container-color--ct-sys-color-surface-container-lowest --ct-table-surface-header-container-color--ct-sys-color-primary-container --ct-table-filled-header-container-color--ct-sys-color-secondary-container --ct-table-tonal-header-container-color
header-headline-color--ct-sys-color-on-surface --ct-table-standard-header-headline-color--ct-sys-color-on-surface --ct-table-surface-header-headline-color--ct-sys-color-on-primary-container --ct-table-filled-header-headline-color--ct-sys-color-on-secondary-container --ct-table-tonal-header-headline-color
header-hover-headline-colorsame as row-item-label-text-color --ct-table-standard-header-hover-headline-colorsame as row-item-label-text-color --ct-table-surface-header-hover-headline-colorsame as row-item-label-text-color --ct-table-filled-header-hover-headline-colorsame as row-item-label-text-color --ct-table-tonal-header-hover-headline-color
header-hover-sorting-icon-button-colorsame as row-item-label-text-color --ct-table-standard-header-hover-sorting-icon-button-colorsame as row-item-label-text-color --ct-table-surface-header-hover-sorting-icon-button-colorsame as row-item-label-text-color --ct-table-filled-header-hover-sorting-icon-button-colorsame as row-item-label-text-color --ct-table-tonal-header-hover-sorting-icon-button-color
on-error-container-color--ct-sys-color-on-error-container --ct-table-standard-on-error-container-color--ct-sys-color-on-error-container --ct-table-surface-on-error-container-color--ct-sys-color-on-error-container --ct-table-filled-on-error-container-color--ct-sys-color-on-error-container --ct-table-tonal-on-error-container-color
outline-color--ct-sys-color-outline-variant --ct-table-standard-outline-color--ct-sys-color-outline-variant --ct-table-surface-outline-color--ct-sys-color-primary --ct-table-filled-outline-color--ct-sys-color-secondary --ct-table-tonal-outline-color
row-item-container-colortransparent --ct-table-standard-row-item-container-color--ct-sys-color-surface-container-lowest --ct-table-surface-row-item-container-color--ct-sys-color-primary-container --ct-table-filled-row-item-container-color--ct-sys-color-secondary-container --ct-table-tonal-row-item-container-color
row-item-hover-state-layer-color--ct-sys-color-on-surface --ct-table-standard-row-item-hover-state-layer-color--ct-sys-color-on-surface --ct-table-surface-row-item-hover-state-layer-color--ct-sys-color-on-primary-container --ct-table-filled-row-item-hover-state-layer-color--ct-sys-color-on-secondary-container --ct-table-tonal-row-item-hover-state-layer-color
row-item-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-standard-row-item-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-surface-row-item-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-filled-row-item-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-tonal-row-item-hover-state-layer-opacity
row-item-label-text-color--ct-sys-color-on-surface --ct-table-standard-row-item-label-text-color--ct-sys-color-on-surface --ct-table-surface-row-item-label-text-color--ct-sys-color-on-primary-container --ct-table-filled-row-item-label-text-color--ct-sys-color-on-secondary-container --ct-table-tonal-row-item-label-text-color
row-item-outline-color--ct-sys-color-outline-variant --ct-table-standard-row-item-outline-color--ct-sys-color-outline-variant --ct-table-surface-row-item-outline-color--ct-sys-color-primary --ct-table-filled-row-item-outline-color--ct-sys-color-secondary --ct-table-tonal-row-item-outline-color
row-item-selected-hover-state-layer-colorsame as row-item-hover-state-layer-color --ct-table-standard-row-item-selected-hover-state-layer-colorsame as row-item-hover-state-layer-color --ct-table-surface-row-item-selected-hover-state-layer-colorsame as row-item-hover-state-layer-color --ct-table-filled-row-item-selected-hover-state-layer-colorsame as row-item-hover-state-layer-color --ct-table-tonal-row-item-selected-hover-state-layer-color
row-item-selected-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-standard-row-item-selected-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-surface-row-item-selected-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-filled-row-item-selected-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-table-tonal-row-item-selected-hover-state-layer-opacity
scrollbar-color--ct-sys-color-outline-variant --ct-table-standard-scrollbar-color--ct-sys-color-outline-variant --ct-table-surface-scrollbar-color--ct-sys-color-primary --ct-table-filled-scrollbar-color--ct-sys-color-secondary --ct-table-tonal-scrollbar-color
scrollbar-thumb-color--ct-sys-color-on-surface-variant --ct-table-standard-scrollbar-thumb-color--ct-sys-color-on-surface-variant --ct-table-surface-scrollbar-thumb-color--ct-sys-color-on-primary-container --ct-table-filled-scrollbar-thumb-color--ct-sys-color-on-secondary-container --ct-table-tonal-scrollbar-thumb-color
scrollbar-thumb-hover-color--ct-sys-color-on-surface --ct-table-standard-scrollbar-thumb-hover-color--ct-sys-color-on-surface --ct-table-surface-scrollbar-thumb-hover-color--ct-sys-color-on-primary --ct-table-filled-scrollbar-thumb-hover-color--ct-sys-color-on-secondary --ct-table-tonal-scrollbar-thumb-hover-color

Other tokens⁠

These stay the same whatever the variant.

TokenValue
--ct-table-caption-text-color--ct-sys-color-on-surface --ct-table-caption-text-color
--ct-table-caption-text-font--ct-sys-typescale-title-medium-font --ct-table-caption-text-font
--ct-table-caption-text-line-height--ct-sys-typescale-title-medium-line-height --ct-table-caption-text-line-height
--ct-table-caption-text-size--ct-sys-typescale-title-medium-size --ct-table-caption-text-size
--ct-table-caption-text-tracking--ct-sys-typescale-title-medium-tracking --ct-table-caption-text-tracking
--ct-table-caption-text-weight--ct-sys-typescale-title-medium-weight --ct-table-caption-text-weight
--ct-table-footer-container-dense-1-height48px --ct-table-footer-container-dense-1-height
--ct-table-footer-container-dense-2-height44px --ct-table-footer-container-dense-2-height
--ct-table-footer-container-dense-3-height40px --ct-table-footer-container-dense-3-height
--ct-table-footer-container-dense-4-height36px --ct-table-footer-container-dense-4-height
--ct-table-footer-container-standard-height52px --ct-table-footer-container-standard-height
--ct-table-header-container-dense-1-height52px --ct-table-header-container-dense-1-height
--ct-table-header-container-dense-2-height48px --ct-table-header-container-dense-2-height
--ct-table-header-container-dense-3-height44px --ct-table-header-container-dense-3-height
--ct-table-header-container-dense-4-height40px --ct-table-header-container-dense-4-height
--ct-table-header-container-standard-height56px --ct-table-header-container-standard-height
--ct-table-header-headline-font--ct-sys-typescale-title-small-font --ct-table-header-headline-font
--ct-table-header-headline-size--ct-sys-typescale-title-small-size --ct-table-header-headline-size
--ct-table-header-headline-weight--ct-sys-typescale-title-small-weight --ct-table-header-headline-weight
--ct-table-outline-width1px --ct-table-outline-width
--ct-table-row-item-label-text-font--ct-sys-typescale-body-medium-font --ct-table-row-item-label-text-font
--ct-table-row-item-label-text-size--ct-sys-typescale-body-medium-size --ct-table-row-item-label-text-size
--ct-table-row-item-label-text-weight--ct-sys-typescale-body-medium-weight --ct-table-row-item-label-text-weight
--ct-table-row-item-outline-width1px --ct-table-row-item-outline-width
--ct-table-row-layers-container-dense-1-height48px --ct-table-row-layers-container-dense-1-height
--ct-table-row-layers-container-dense-2-height44px --ct-table-row-layers-container-dense-2-height
--ct-table-row-layers-container-dense-3-height40px --ct-table-row-layers-container-dense-3-height
--ct-table-row-layers-container-dense-4-height36px --ct-table-row-layers-container-dense-4-height
--ct-table-row-layers-container-standard-height52px --ct-table-row-layers-container-standard-height

Names and states⁠

A screen reader announces the data grid as a grid of rows, column headers, and cells. It follows the WAI-ARIA Authoring Practices: Grid (Interactive Tabular Data and Layout Containers) Pattern.

  • The accessible name comes from grid-label, or from a caption inside the grid.
  • An aria-label set on the grid has no effect. Set grid-label or add a caption.
  • A screen reader announces the total row and column counts, and the position of each row counting the header, so the first data row is row 2. A virtualized grid is announced as busy while a window of rows loads.
  • While selectable is set, a screen reader announces each cell as selected or not in cell mode, and each row in row mode. Without it, nothing is announced as selected.
  • A sortable column header is announced with its sort state and a label such as "Name, column 1 of 4, sortable, not sorted". Each sort is announced in a live region, for example "Sorted by Name, ascending".
  • Loads are announced in a polite live region: "Loading data", "Loaded 20 rows", "No data to display", and "Error loading data".
  • Give every row a stable key with unique-identifier. The grid logs an error without it and drops keyboard focus on every data change.
  • For read-only data that readers browse rather than navigate, a data table suits the job better.

Keyboard and focus⁠

Key Action
Tab Moves focus into the grid, which takes one Tab stop, and out of it
Arrow keys Move to the adjacent cell in cell mode; Up and Down move between rows in row mode, where Left and Right do nothing
Home, End Move to the first or last cell of the row (cell mode)
Ctrl+Home, Ctrl+End Move to the first or last cell of the grid (cell mode)
PageUp, PageDown Move by one visible page of rows (cell mode)
Up Arrow from the first row Enters the header row (cell mode); Down Arrow returns to the first row
Enter, Space Select the focused cell or row while selectable is set; on a header, sort by that column (cell mode)

The component handles every key above itself; only Tab is the browser's own behavior.

  • The grid draws a focus ring on keyboard focus.
  • Row mode leaves the header out of keyboard reach, so sorting is pointer-only there. Use navigation-mode cell when readers need to sort by keyboard, or offer another way to call sort().
  • In a selectable grid, Enter selects a cell and does not activate a cell action.
  • After a refresh, a window load, or a sort, focus returns to the same record, found by unique-identifier.

Pointer and touch⁠

  • Rows are 52 pixels tall at the default density and 36 pixels at the densest, so each row clears the 24 by 24 pixel minimum of WCAG 2.5.8 in height. The density examples show each step.
  • A column can be narrower than 24 pixels. Give a column that holds an action a minWidth that keeps its control at least 24 pixels wide.

Display settings⁠

  • Forced colors: row dividers stay visible and take a system color.
  • Right-to-left: the arrow keys do not swap. Left Arrow always moves toward the first column and Right Arrow toward the last.
  • Reduced motion: the sort arrow's fade and rotation run only when the reader has not asked for reduced motion.

Standards⁠

With its defaults, the data grid meets three WCAG 2.2 success criteria:

  • 1.3.1 Info and Relationships (A)
  • 2.1.2 No Keyboard Trap (A)
  • 2.4.7 Focus Visible (AA)

Three more depend on how you use it:

  • 2.1.1 Keyboard (A): in row mode, give readers a keyboard route to sorting, or use cell mode.
  • 2.5.8 Target Size (Minimum) (AA): give action columns a minWidth that keeps each control at least 24 pixels wide.
  • 4.1.2 Name, Role, Value (A): set grid-label or add a caption so the grid has a name.