Data table
A data table shows read-only rows and columns, so readers can compare values and screen readers can browse them. Choose whether a phone sees a table that scrolls sideways or rows restacked as labeled blocks; sorting needs no wiring beyond marking a column sortable. Each table below wears its own variant and density.
| Seed | Mood |
|---|---|
| Cobalt | Calm |
| Vermilion | Bold |
| Dish | Price | Heat |
|---|---|---|
| Laksa | $11 | Hot |
| Soba | $9 | Mild |
| Team | Points |
|---|---|
| Otters | 42 |
| Herons | 37 |
| Task | Owner |
|---|---|
| Login | Ada |
| Docs | Grace |
| Drink | Price |
|---|---|
| Latte | $4 |
| Cortado | $4 |
| Mocha | $6 |
| Track | Time |
|---|---|
| Kite | 3:12 |
| Track | Time |
|---|---|
| Lantern | 2:48 |
Reference docs
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 table stands out from the page, from most to least:
- Filled: a table that is the focus of its section, such as a price list on a pricing page, on the primary container color.
- Tonal: a table that supports nearby content, such as a usage summary beside a chart, on the secondary container color.
- Surface: a table that needs its own ground, such as a list in a panel of another color, on the lowest surface container color.
- Standard: the default, with no fill, for a table that sits directly on the page or inside a card, such as an invoice list, and takes that container's color.
Built in
- A column marked
sortablein sorts when its header is activated, and a screen reader announces the new order.columns restacks each row as a block with every value beside its column title, so a narrow screen needs no sideways scrolling.stack keeps every word of a long cell readable, by growing the row rather than cutting the text.wrap-cells keeps a table of thousands of rows light.virtualize- Markup you already have works: a table written inside the element becomes a data table.
puts your own content in a cell, such as a link or a status label, through a child with atemplateFieldscell:slot name.
Using data tables well
- Give a numeric column the
numberorcurrencytype, so its values sit at the end of the cell, and leave text columns at the start. - Give a
currencycolumn its currency code, such as"currency": "EUR". The table's decides how a price is written, not which currency it is in, and a column with no code shows plain numbers.locale - Keep column titles short, and move any explanation to the caption.
- Put paging controls in a footer below the table, with a rows-per-page choice and a position readout such as 1–10 of 100, and slice the data yourself when the page changes.
- Choose a data grid when rows need selecting, since a data table has no selection and no checkbox column.
- Set
tostack for a table people open on a phone, and leave it at the default for a table whose columns must stay aligned.auto
These rules follow Material 3 Expressive's guidance for data tables, on material.io.
Variants
variantstandard
Caption position
The default slot holds the caption, which also serves as the table's name. caption-positionleadinggrid-label
Density
density0 (the roomiest) to 4 (the tightest), five values in all. Omit it and the table takes the density from your style configuration, which is standard
Stack
stackneveralwaysauto
Columns and rows
itemscolumnscolumnssortable and its header becomes a button; activating it cycles through ascending, descending, and unsorted. Set unique-identifier
Lines and stripes
stripedshow-column-dividersborderless
Wrapping text
By default a cell truncates text that does not fit. wrap-cells
Cell content
templateFieldsslot="cell:{rowKey}:{field}" for each cell, where rowKey is the row's value in the unique-identifier
Large data sets
virtualizeoverscan-countitemsProvidervirtualize
Written table
A <table> written inside the element is its source, so crawlers and readers without script still see the rows. Header cells take options such as data-cw-field and data-cw-sortable.
Properties
| Property | Attribute | Type | Description |
|---|---|---|---|
borderless | borderless | booleandefault false | Removes the table's outer frame. The header's underline stays, drawn in the row divider's color and width, as do the row and cell dividers. See Lines and stripes. |
captionPosition | caption-positionleading, trailing | CaptionPositionCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configuration | The caption's position in relation to the component. See Caption position. |
columns | ColumnDefinition[]default [] | Column definitions. If not provided, columns will be auto-generated from data (if possible). See Columns and rows. | |
density | density0, 1, 2, 3, 4 | DensityDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configuration | How tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density. |
gridLabel | grid-label | string | The name a screen reader announces for the component. See Caption position. |
items | TItem[]default [] | Data source as an array of objects. Use this for client-side data. See Columns and rows. | |
itemsProvider | GridItemsProvider<TItem> | Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets. | |
locale | locale | string | 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. |
overscanCount | overscan-count | numberdefault 3 | How 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. |
showColumnDividers | show-column-dividers | booleandefault false | Shows vertical dividers between columns, which helps tell columns apart when there are many. See Lines and stripes. |
stack | stacknever, always, auto | TableStackTableStack.Never, .Always, .Autodefault TableStack.Never | How the table fits a narrow width. always draws each row as a block, with every value beside its column's title; auto does so only while the table cannot show its content at the width it has, measured with its rows as rows.Has no effect while virtualize is set: virtualized rows share one height, and a row drawn as a block is as tall as its content. See Stack. |
striped | striped | booleandefault false | Shades alternate rows. See Lines and stripes. |
templateFields | string[]default [] | The fields whose cells show content the page supplies, through a child with slot="cell:{rowKey}:{field}", rather than their value. Every cell of such a field shows its slot, so the content can arrive after the row is drawn; rows-change names the rows drawn. {rowKey} is the row's value in the uniqueIdentifier field, which these fields need.A written <table> needs no list: any written cell with such a child shows it in place of its copy. See Cell content. | |
uniqueIdentifier | unique-identifier | string | The name of a field whose value identifies a row. Optional, except when templateFields is set. Without it, the table cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Columns and rows, Cell content. |
variant | variantfilled, standard, surface, tonal | TableVariantTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configuration | The 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. |
virtualize | virtualize | booleandefault false | Shows only the rows in view, for large datasets. Every row must be the same height. See Large data sets. |
wrapCells | wrap-cells | booleandefault false | Cells wrap their text rather than truncating it. Rows grow to fit, the row height becomes a minimum, columns size to their content and the table scrolls sideways when its content is wider than its space.Has no effect while virtualize is set, for the reason stack gives. See Wrapping text. |
When itemsitemsProvideritemsitemsvirtualize
Slots
| Slot | Description |
|---|---|
| (default) | Caption content displayed above or below the table. Not rendered while a written <table> is the source; its <caption> is shown instead. |
A child with slot name cell:{rowKey}:{field} fills one cell; see templateFieldsgrid-label
Events
| Event | Type | Detail | Description |
|---|---|---|---|
sort-change | SortChangeEvent | SortChangeEventDetail | Dispatched when the sort state changes (a sortable column header is activated). It bubbles and is composed. |
rows-change | RowsChangeEvent | RowsChangeEventDetail | Dispatched when the rows drawn change, naming each drawn row's key in order, so a page can supply cell-slot content for the drawn rows alone. It bubbles and is composed. |
cell-activate | CellActivateEvent | CellActivateEventDetail<TItem> | Dispatched when a control rendered by ColumnDefinition.actionLabel/actionHref is activated — by pointer, Enter, or Space. It bubbles and is composed. |
With itemsitemsProvidersortDescriptors, and the provider must sort.
Props
| Prop | Type | Description |
|---|---|---|
borderless | booleandefault false | Removes the table's outer frame. The header's underline stays, drawn in the row divider's color and width, as do the row and cell dividers. See Lines and stripes. |
captionPosition | CaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configuration | The caption's position in relation to the component. See Caption position. |
columns | ColumnDefinition[]default [] | Column definitions. If not provided, columns will be auto-generated from data (if possible). See Columns and rows. |
density | DensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configuration | How tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density. |
gridLabel | string | The name a screen reader announces for the component. See Caption position. |
items | TItem[]default [] | Data source as an array of objects. Use this for client-side data. See Columns and rows. |
itemsProvider | GridItemsProvider<TItem> | Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets. |
locale | string | 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. |
overscanCount | numberdefault 3 | How 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. |
showColumnDividers | booleandefault false | Shows vertical dividers between columns, which helps tell columns apart when there are many. See Lines and stripes. |
stack | TableStackTypeTableStack.Never, .Always, .Autodefault TableStack.Never | How the table fits a narrow width. always draws each row as a block, with every value beside its column's title; auto does so only while the table cannot show its content at the width it has, measured with its rows as rows.Has no effect while virtualize is set: virtualized rows share one height, and a row drawn as a block is as tall as its content. See Stack. |
striped | booleandefault false | Shades alternate rows. See Lines and stripes. |
templateFields | string[]default [] | The fields whose cells show content the page supplies, through a child with slot="cell:{rowKey}:{field}", rather than their value. Every cell of such a field shows its slot, so the content can arrive after the row is drawn; rows-change names the rows drawn. {rowKey} is the row's value in the uniqueIdentifier field, which these fields need.A written <table> needs no list: any written cell with such a child shows it in place of its copy. See Cell content. |
uniqueIdentifier | string | The name of a field whose value identifies a row. Optional, except when templateFields is set. Without it, the table cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Columns and rows, Cell content. |
variant | TableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configuration | The 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. |
virtualize | booleandefault false | Shows only the rows in view, for large datasets. Every row must be the same height. See Large data sets. |
wrapCells | booleandefault false | Cells wrap their text rather than truncating it. Rows grow to fit, the row height becomes a minimum, columns size to their content and the table scrolls sideways when its content is wider than its space.Has no effect while virtualize is set, for the reason stack gives. See Wrapping text. |
When itemsitemsProvideritemsitemsvirtualize
Children
| Child | Description |
|---|---|
children | Caption content displayed above or below the table. Not rendered while a written <table> is the source; its <caption> is shown instead. |
A child with slot name cell:{rowKey}:{field} fills one cell; see templateFieldsgrid-label
Events
| Prop | Argument | Description |
|---|---|---|
onSortChange | SortChangeEvent | Dispatched when the sort state changes (a sortable column header is activated). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors. |
onRowsChange | RowsChangeEvent | Dispatched when the rows drawn change, naming each drawn row's key in order, so a page can supply cell-slot content for the drawn rows alone. It bubbles and is composed. Its detail carries keys. |
onCellActivate | CellActivateEvent<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. |
With itemsitemsProvidersortDescriptors, and the provider must sort.
Parameters
| Parameter | Type | Description |
|---|---|---|
Borderless | bool?default false | Removes the table's outer frame. The header's underline stays, drawn in the row divider's color and width, as do the row and cell dividers. See Lines and stripes. |
CaptionPosition | CaptionPosition?CaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configuration | The caption's position in relation to the component. See Caption position. |
Columns | IEnumerable<ColumnDefinition>?default [] | Column definitions. If not provided, columns will be auto-generated from data (if possible). See Columns and rows. |
Density | Density?Density.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configuration | How tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density. |
GridLabel | string? | The name a screen reader announces for the component. See Caption position. |
Items | IEnumerable<TItem>?default [] | Data source as an array of objects. Use this for client-side data. See Columns and rows. |
ItemsProvider | GridItemsProvider<TItem>? | Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while Items has rows. See Large data sets. |
Locale | string? | 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. |
OverscanCount | int?default 3 | How 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. |
ShowColumnDividers | bool?default false | Shows vertical dividers between columns, which helps tell columns apart when there are many. See Lines and stripes. |
Stack | TableStack?TableStack.Never, .Always, .Autodefault TableStack.Never | How the table fits a narrow width. always draws each row as a block, with every value beside its column's title; auto does so only while the table cannot show its content at the width it has, measured with its rows as rows.Has no effect while Virtualize is set: virtualized rows share one height, and a row drawn as a block is as tall as its content. See Stack. |
Striped | bool?default false | Shades alternate rows. See Lines and stripes. |
TemplateFields | IEnumerable<string>?default [] | The fields whose cells show content the page supplies, through a child with slot="cell:{rowKey}:{field}", rather than their value. Every cell of such a field shows its slot, so the content can arrive after the row is drawn; rows-change names the rows drawn. {rowKey} is the row's value in the UniqueIdentifier field, which these fields need.A written <table> needs no list: any written cell with such a child shows it in place of its copy. See Cell content. |
UniqueIdentifier | string? | The name of a field whose value identifies a row. Optional, except when TemplateFields is set. Without it, the table cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Columns and rows, Cell content. |
Variant | TableVariant?TableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configuration | The 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. |
Virtualize | bool?default false | Shows only the rows in view, for large datasets. Every row must be the same height. See Large data sets. |
WrapCells | bool?default false | Cells wrap their text rather than truncating it. Rows grow to fit, the row height becomes a minimum, columns size to their content and the table scrolls sideways when its content is wider than its space.Has no effect while Virtualize is set, for the reason Stack gives. See Wrapping text. |
When itemsitemsProvideritemsitemsvirtualize
Render fragments
| Parameter | Type | Description |
|---|---|---|
ChildContent | RenderFragment? | Caption content displayed above or below the table. Not rendered while a written <table> is the source; its <caption> is shown instead. |
A child with slot name cell:{rowKey}:{field} fills one cell; see templateFieldsgrid-label
Event callbacks
| Parameter | Type | Description |
|---|---|---|
OnSortChange | EventCallback<SortChangeEventArgs> | Dispatched when the sort state changes (a sortable column header is activated). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors. |
OnRowsChange | EventCallback<RowsChangeEventArgs> | Dispatched when the rows drawn change, naming each drawn row's key in order, so a page can supply cell-slot content for the drawn rows alone. It bubbles and is composed. Its detail carries keys. |
OnCellActivate | EventCallback<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. |
With itemsitemsProvidersortDescriptors, and the provider must sort.
Inputs
| Input | Type | Description |
|---|---|---|
borderless | booleandefault false | Removes the table's outer frame. The header's underline stays, drawn in the row divider's color and width, as do the row and cell dividers. See Lines and stripes. |
captionPosition | CaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configuration | The caption's position in relation to the component. See Caption position. |
columns | ColumnDefinition[]default [] | Column definitions. If not provided, columns will be auto-generated from data (if possible). See Columns and rows. |
density | DensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configuration | How tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density. |
gridLabel | string | The name a screen reader announces for the component. See Caption position. |
items | TItem[]default [] | Data source as an array of objects. Use this for client-side data. See Columns and rows. |
itemsProvider | GridItemsProvider<TItem> | Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets. |
locale | string | 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. |
overscanCount | numberdefault 3 | How 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. |
showColumnDividers | booleandefault false | Shows vertical dividers between columns, which helps tell columns apart when there are many. See Lines and stripes. |
stack | TableStackTypeTableStack.Never, .Always, .Autodefault TableStack.Never | How the table fits a narrow width. always draws each row as a block, with every value beside its column's title; auto does so only while the table cannot show its content at the width it has, measured with its rows as rows.Has no effect while virtualize is set: virtualized rows share one height, and a row drawn as a block is as tall as its content. See Stack. |
striped | booleandefault false | Shades alternate rows. See Lines and stripes. |
templateFields | string[]default [] | The fields whose cells show content the page supplies, through a child with slot="cell:{rowKey}:{field}", rather than their value. Every cell of such a field shows its slot, so the content can arrive after the row is drawn; rows-change names the rows drawn. {rowKey} is the row's value in the uniqueIdentifier field, which these fields need.A written <table> needs no list: any written cell with such a child shows it in place of its copy. See Cell content. |
uniqueIdentifier | string | The name of a field whose value identifies a row. Optional, except when templateFields is set. Without it, the table cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Columns and rows, Cell content. |
variant | TableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configuration | The 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. |
virtualize | booleandefault false | Shows only the rows in view, for large datasets. Every row must be the same height. See Large data sets. |
wrapCells | booleandefault false | Cells wrap their text rather than truncating it. Rows grow to fit, the row height becomes a minimum, columns size to their content and the table scrolls sideways when its content is wider than its space.Has no effect while virtualize is set, for the reason stack gives. See Wrapping text. |
When itemsitemsProvideritemsitemsvirtualize
Content projection
| Content | Description |
|---|---|
content with no slot | Caption content displayed above or below the table. Not rendered while a written <table> is the source; its <caption> is shown instead. |
A child with slot name cell:{rowKey}:{field} fills one cell; see templateFieldsgrid-label
Outputs
| Output | Event | Description |
|---|---|---|
cwSortChange | SortChangeEvent | Dispatched when the sort state changes (a sortable column header is activated). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors. |
cwRowsChange | RowsChangeEvent | Dispatched when the rows drawn change, naming each drawn row's key in order, so a page can supply cell-slot content for the drawn rows alone. It bubbles and is composed. Its detail carries keys. |
cwCellActivate | CellActivateEvent | 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. |
With itemsitemsProvidersortDescriptors, and the provider must sort.
Props
| Prop | Type | Description |
|---|---|---|
borderless | booleandefault false | Removes the table's outer frame. The header's underline stays, drawn in the row divider's color and width, as do the row and cell dividers. See Lines and stripes. |
captionPosition | CaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configuration | The caption's position in relation to the component. See Caption position. |
columns | ColumnDefinition[]default [] | Column definitions. If not provided, columns will be auto-generated from data (if possible). See Columns and rows. |
density | DensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configuration | How tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density. |
gridLabel | string | The name a screen reader announces for the component. See Caption position. |
items | TItem[]default [] | Data source as an array of objects. Use this for client-side data. See Columns and rows. |
itemsProvider | GridItemsProvider<TItem> | Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets. |
locale | string | 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. |
overscanCount | numberdefault 3 | How 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. |
showColumnDividers | booleandefault false | Shows vertical dividers between columns, which helps tell columns apart when there are many. See Lines and stripes. |
stack | TableStackTypeTableStack.Never, .Always, .Autodefault TableStack.Never | How the table fits a narrow width. always draws each row as a block, with every value beside its column's title; auto does so only while the table cannot show its content at the width it has, measured with its rows as rows.Has no effect while virtualize is set: virtualized rows share one height, and a row drawn as a block is as tall as its content. See Stack. |
striped | booleandefault false | Shades alternate rows. See Lines and stripes. |
templateFields | string[]default [] | The fields whose cells show content the page supplies, through a child with slot="cell:{rowKey}:{field}", rather than their value. Every cell of such a field shows its slot, so the content can arrive after the row is drawn; rows-change names the rows drawn. {rowKey} is the row's value in the uniqueIdentifier field, which these fields need.A written <table> needs no list: any written cell with such a child shows it in place of its copy. See Cell content. |
uniqueIdentifier | string | The name of a field whose value identifies a row. Optional, except when templateFields is set. Without it, the table cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Columns and rows, Cell content. |
variant | TableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configuration | The 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. |
virtualize | booleandefault false | Shows only the rows in view, for large datasets. Every row must be the same height. See Large data sets. |
wrapCells | booleandefault false | Cells wrap their text rather than truncating it. Rows grow to fit, the row height becomes a minimum, columns size to their content and the table scrolls sideways when its content is wider than its space.Has no effect while virtualize is set, for the reason stack gives. See Wrapping text. |
When itemsitemsProvideritemsitemsvirtualize
Slots
| Slot | Description |
|---|---|
default | Caption content displayed above or below the table. Not rendered while a written <table> is the source; its <caption> is shown instead. |
A child with slot name cell:{rowKey}:{field} fills one cell; see templateFieldsgrid-label
Events
| Event | Type | Description |
|---|---|---|
sortChange | SortChangeEvent | Dispatched when the sort state changes (a sortable column header is activated). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors. |
rowsChange | RowsChangeEvent | Dispatched when the rows drawn change, naming each drawn row's key in order, so a page can supply cell-slot content for the drawn rows alone. It bubbles and is composed. Its detail carries keys. |
cellActivate | CellActivateEvent | 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. |
With itemsitemsProvidersortDescriptors, and the provider must sort.
Props
| Prop | Type | Description |
|---|---|---|
borderless | booleandefault false | Removes the table's outer frame. The header's underline stays, drawn in the row divider's color and width, as do the row and cell dividers. See Lines and stripes. |
captionPosition | CaptionPositionTypeCaptionPosition.Leading, .Trailingdefault CaptionPosition.Leading, from the style configuration | The caption's position in relation to the component. See Caption position. |
columns | ColumnDefinition[]default [] | Column definitions. If not provided, columns will be auto-generated from data (if possible). See Columns and rows. |
density | DensityTypeDensity.Standard, .Dense1, .Dense2, .Dense3, .Dense4default Density.Standard, from the style configuration | How tightly rows are spaced, from 0, the roomiest, to 4, the tightest. See Density. |
gridLabel | string | The name a screen reader announces for the component. See Caption position. |
items | TItem[]default [] | Data source as an array of objects. Use this for client-side data. See Columns and rows. |
itemsProvider | GridItemsProvider<TItem> | Async function to provide data. Use this for server-side operations (filtering, sorting, paging). Ignored while items has rows. See Large data sets. |
locale | string | 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. |
overscanCount | numberdefault 3 | How 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. |
showColumnDividers | booleandefault false | Shows vertical dividers between columns, which helps tell columns apart when there are many. See Lines and stripes. |
stack | TableStackTypeTableStack.Never, .Always, .Autodefault TableStack.Never | How the table fits a narrow width. always draws each row as a block, with every value beside its column's title; auto does so only while the table cannot show its content at the width it has, measured with its rows as rows.Has no effect while virtualize is set: virtualized rows share one height, and a row drawn as a block is as tall as its content. See Stack. |
striped | booleandefault false | Shades alternate rows. See Lines and stripes. |
templateFields | string[]default [] | The fields whose cells show content the page supplies, through a child with slot="cell:{rowKey}:{field}", rather than their value. Every cell of such a field shows its slot, so the content can arrive after the row is drawn; rows-change names the rows drawn. {rowKey} is the row's value in the uniqueIdentifier field, which these fields need.A written <table> needs no list: any written cell with such a child shows it in place of its copy. See Cell content. |
uniqueIdentifier | string | The name of a field whose value identifies a row. Optional, except when templateFields is set. Without it, the table cannot restore keyboard focus to the same row after a sort, filter or page change, so it drops focus. See Columns and rows, Cell content. |
variant | TableVariantTypeTableVariant.Filled, .Standard, .Surface, .Tonaldefault TableVariant.Standard, from the style configuration | The 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. |
virtualize | booleandefault false | Shows only the rows in view, for large datasets. Every row must be the same height. See Large data sets. |
wrapCells | booleandefault false | Cells wrap their text rather than truncating it. Rows grow to fit, the row height becomes a minimum, columns size to their content and the table scrolls sideways when its content is wider than its space.Has no effect while virtualize is set, for the reason stack gives. See Wrapping text. |
When itemsitemsProvideritemsitemsvirtualize
Snippets
| Snippet | Description |
|---|---|
children | Caption content displayed above or below the table. Not rendered while a written <table> is the source; its <caption> is shown instead. |
A child with slot name cell:{rowKey}:{field} fills one cell; see templateFieldsgrid-label
Events
| Prop | Type | Description |
|---|---|---|
onSortChange | SortChangeEvent | Dispatched when the sort state changes (a sortable column header is activated). It bubbles and is composed. Its detail carries column, direction, and sortDescriptors. |
onRowsChange | RowsChangeEvent | Dispatched when the rows drawn change, naming each drawn row's key in order, so a page can supply cell-slot content for the drawn rows alone. It bubbles and is composed. Its detail carries keys. |
onCellActivate | CellActivateEvent | 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. |
With itemsitemsProvidersortDescriptors, and the provider must sort.
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
| Name | standard | surface | filled | tonal |
|---|---|---|---|---|
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-color | transparent --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-color | same as row-item-label-text-color --ct-table-standard-header-hover-headline-color | same as row-item-label-text-color --ct-table-surface-header-hover-headline-color | same as row-item-label-text-color --ct-table-filled-header-hover-headline-color | same as row-item-label-text-color --ct-table-tonal-header-hover-headline-color |
header-hover-sorting-icon-button-color | same as row-item-label-text-color --ct-table-standard-header-hover-sorting-icon-button-color | same as row-item-label-text-color --ct-table-surface-header-hover-sorting-icon-button-color | same as row-item-label-text-color --ct-table-filled-header-hover-sorting-icon-button-color | same 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-color | transparent --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-color | same as row-item-hover-state-layer-color --ct-table-standard-row-item-selected-hover-state-layer-color | same as row-item-hover-state-layer-color --ct-table-surface-row-item-selected-hover-state-layer-color | same as row-item-hover-state-layer-color --ct-table-filled-row-item-selected-hover-state-layer-color | same 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.
| Token | Value |
|---|---|
--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-height | 48px --ct-table-footer-container-dense-1-height |
--ct-table-footer-container-dense-2-height | 44px --ct-table-footer-container-dense-2-height |
--ct-table-footer-container-dense-3-height | 40px --ct-table-footer-container-dense-3-height |
--ct-table-footer-container-dense-4-height | 36px --ct-table-footer-container-dense-4-height |
--ct-table-footer-container-standard-height | 52px --ct-table-footer-container-standard-height |
--ct-table-header-container-dense-1-height | 52px --ct-table-header-container-dense-1-height |
--ct-table-header-container-dense-2-height | 48px --ct-table-header-container-dense-2-height |
--ct-table-header-container-dense-3-height | 44px --ct-table-header-container-dense-3-height |
--ct-table-header-container-dense-4-height | 40px --ct-table-header-container-dense-4-height |
--ct-table-header-container-standard-height | 56px --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-header-sticky-offset | 0px --ct-table-header-sticky-offset |
--ct-table-outline-width | 1px --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-width | 1px --ct-table-row-item-outline-width |
--ct-table-row-layers-container-dense-1-height | 48px --ct-table-row-layers-container-dense-1-height |
--ct-table-row-layers-container-dense-2-height | 44px --ct-table-row-layers-container-dense-2-height |
--ct-table-row-layers-container-dense-3-height | 40px --ct-table-row-layers-container-dense-3-height |
--ct-table-row-layers-container-dense-4-height | 36px --ct-table-row-layers-container-dense-4-height |
--ct-table-row-layers-container-standard-height | 52px --ct-table-row-layers-container-standard-height |
Names and states
A screen reader announces a data table as a table with a header row. It follows the WAI-ARIA Authoring Practices: Table pattern, a static table with no cell navigation.
- The caption is the first source of the name. Without one,
names it, and a written table falls back to its owngrid-labelaria-label. - An
aria-labelset on the data table has no effect. Give the table a caption or .grid-label - A screen reader announces the row and column counts, and reads each header cell as a column header.
- A sortable header is a button named for its column, and a screen reader announces its sort state. The sort arrow itself is not announced.
- A sort is announced in a live region, such as "Sorted by Customer, ascending". Loads announce "Loading data", "Loaded 3 rows", and "No data to display".
- Choose a data grid when readers must move between cells by keyboard or select rows. A data table has no cell roles.
Keyboard and focus
| Key | Action |
|---|---|
| Tab | Moves to the next control in the table, such as a sort button, a cell action, or your own content. |
| Shift+Tab | Moves to the previous control. |
| Enter | Activates the focused sort button or cell action. |
| Space | Activates the focused sort button or cell action. |
These are the keys of an ordinary button or link; the table adds no keys of its own.
- A sort button shows a focus ring on keyboard focus.
- Cells are not focusable. Only interactive content inside cells is in the Tab order.
- A table that scrolls takes one Tab stop, announced as a group named by
or "Scrollable table", so keyboard users can scroll it. A table that does not scroll takes no Tab stop.grid-label
Pointer and touch
- The sort arrow is always visible, so touch users can see that a header is interactive.
- Keep controls you place in cells, such as buttons from cell content, at least 24 by 24 pixels, the minimum in WCAG 2.5.8.
Display settings
- Forced colors: row dividers stay visible and take a system color.
- Reduced motion: the table has no animation, so the setting changes nothing.
- Right-to-left: text columns start at the inline edge, which is the right edge in a right-to-left layout.
Standards
With its defaults, a data table meets four WCAG 2.2 success criteria:
- 1.3.1 Info and Relationships (A)
- 2.1.1 Keyboard (A)
- 2.4.7 Focus Visible (AA)
- 4.1.2 Name, Role, Value (A)
Three more depend on how you use it:
- 1.1.1 Non-text Content (A): give every image in a cell a text alternative, or an empty
altwhen it is decorative. - 2.4.6 Headings and Labels (AA): give the table a caption or
that describes its content, and keep column titles short.grid-label - 2.5.8 Target Size (Minimum) (AA): keep every control you place in a cell at least 24 by 24 pixels.