Default

Click a column header to sort ascending; click again to sort descending. Use the filter input to search across all columns.

15 rows
LanguageParadigmFirst appearedType systemWeekly downloads
TypeScriptMulti-paradigm2012Static53200000
JavaScriptMulti-paradigm1995Dynamic61800000
PythonMulti-paradigm1991Dynamic29400000
RustMulti-paradigm2015Static4600000
GoConcurrent2009Static5100000
1–5 of 15
const columns = [
  { key: 'name',     label: 'Language',         sortable: true },
  { key: 'paradigm', label: 'Paradigm',          sortable: true },
  { key: 'year',     label: 'First appeared',    sortable: true, align: 'right' },
  { key: 'typing',   label: 'Type system',       sortable: true },
  { key: 'weekly',   label: 'Weekly downloads',  sortable: true, align: 'right' },
]

<DataTable columns={columns} data={languages} rowsPerPage={5} />

Striped rows + hover highlight

striped accepts true (same as 'odd'), 'odd', or 'even' to control which rows are shaded.

15 rows
LanguageParadigmFirst appearedType systemWeekly downloads
TypeScriptMulti-paradigm2012Static53200000
JavaScriptMulti-paradigm1995Dynamic61800000
PythonMulti-paradigm1991Dynamic29400000
RustMulti-paradigm2015Static4600000
GoConcurrent2009Static5100000
1–5 of 15
{/* striped="odd" and striped={true} are equivalent */}
<DataTable columns={columns} data={data} rowsPerPage={5} striped highlightOnHover />
<DataTable columns={columns} data={data} rowsPerPage={5} striped="even" />

Borders

Add an outer table border, column dividers, or remove the default row borders.

LanguageParadigmTyping
TypeScriptMulti-paradigmStatic
JavaScriptMulti-paradigmDynamic
PythonMulti-paradigmDynamic
RustMulti-paradigmStatic
GoConcurrentStatic
<DataTable columns={columns} data={data} withTableBorder withColumnBorders />

{/* Remove the default row borders */}
<DataTable columns={columns} data={data} withRowBorders={false} />

{/* Custom border color */}
<DataTable columns={columns} data={data} withTableBorder borderColor="var(--dv-color-primary-filled)" />

Cell spacing

Control the padding inside cells with horizontalSpacing and verticalSpacing. Accepts any theme size token or a CSS string.

LanguageParadigmYear
TypeScriptMulti-paradigm2012
JavaScriptMulti-paradigm1995
PythonMulti-paradigm1991
RustMulti-paradigm2015
GoConcurrent2009
<DataTable
  columns={columns}
  data={data}
  horizontalSpacing="lg"
  verticalSpacing="md"
/>

No pagination

Set rowsPerPage={0} to show all rows at once without pagination controls.

6 rows
LanguageYearTyping
TypeScript2012Static
JavaScript1995Dynamic
Python1991Dynamic
Rust2015Static
Go2009Static
Kotlin2011Static
<DataTable columns={columns} data={data} rowsPerPage={0} />

Scoped filter

By default the filter searches across all column keys. Pass filterKeys to limit which columns are matched.

15 rows
LanguageParadigmFirst appearedType systemWeekly downloads
TypeScriptMulti-paradigm2012Static53200000
JavaScriptMulti-paradigm1995Dynamic61800000
PythonMulti-paradigm1991Dynamic29400000
RustMulti-paradigm2015Static4600000
GoConcurrent2009Static5100000
1–5 of 15
{/* Filter only matches name and paradigm, not year/downloads */}
<DataTable columns={columns} data={data} filterKeys={['name', 'paradigm']} />

Without filter

Set withFilter={false} to hide the search input entirely.

LanguageYear
TypeScript2012
JavaScript1995
Python1991
Rust2015
Go2009
1–5 of 5
<DataTable columns={columns} data={data} withFilter={false} />

Caption

Captions render below the table by default. Set captionSide="top" to place the caption above.

Programming languages by type system
LanguageTyping
TypeScriptStatic
JavaScriptDynamic
PythonDynamic
RustStatic
GoStatic
<DataTable
  columns={columns}
  data={data}
  caption="Programming languages by type system"
  captionSide="top"
/>

Fixed layout with column widths

layout="fixed" switches to CSS table-layout: fixed. Column widths are determined by the first row rather than cell content, so the browser can render without scanning every cell — useful for large datasets. Use the width field on each column definition for precise control.

LanguageParadigmTyping
TypeScriptMulti-paradigmStatic
JavaScriptMulti-paradigmDynamic
PythonMulti-paradigmDynamic
RustMulti-paradigmStatic
GoConcurrentStatic
KotlinMulti-paradigmStatic
const columns = [
  { key: 'name',     label: 'Language',  sortable: true, width: '40%' },
  { key: 'paradigm', label: 'Paradigm',  sortable: true, width: '35%' },
  { key: 'typing',   label: 'Typing',    sortable: true, width: '25%' },
]

<DataTable columns={columns} data={data} layout="fixed" />

Row selection

Add selectable to enable a checkbox column. The select-all header checkbox operates on all filtered rows, not just the current page. The toolbar count switches to "N of M selected" while rows are selected. Provide rowKey when your data has a stable unique field — omitting it uses row object reference which is safe as long as the data array doesn't change.

8 rows
LanguageParadigmType system
TypeScriptMulti-paradigmStatic
JavaScriptMulti-paradigmDynamic
PythonMulti-paradigmDynamic
RustMulti-paradigmStatic
GoConcurrentStatic
1–5 of 8
<DataTable columns={columns} data={data} selectable rowKey="name" />

Listening for selection changes

The dv-row-select event fires on the component root whenever the selection changes. event.detail.keys contains the selected key values; event.detail.rows contains the full matching row objects.

<DataTable id="lang-table" columns={columns} data={data} selectable rowKey="name" />

<script>
  document.getElementById('lang-table').addEventListener('dv-row-select', (e) => {
    const { keys, rows } = e.detail
    console.log('Selected keys:', keys)   // ['TypeScript', 'Rust']
    console.log('Selected rows:', rows)   // [{ name: 'TypeScript', ... }, ...]
  })
</script>

Props

PropTypeDefaultDescription
columnsDataTableColumn[]Column definitions — see table below
dataRecord<string, unknown>[][]Row objects — values are coerced to strings for display
rowsPerPagenumber10Rows per page. Set to 0 to disable pagination
filterKeysstring[]all columnsWhich column keys the text filter searches
withFilterbooleantrueShow or hide the text filter input
stripedboolean | 'odd' | 'even'falseAlternating row shading. true is equivalent to 'odd'
highlightOnHoverbooleanfalseHighlight rows on mouse-over
withTableBorderbooleanfalseAdds a border around the entire table
withColumnBordersbooleanfalseAdds vertical borders between columns
withRowBordersbooleantrueShows horizontal borders between rows
borderColorstringCSS color value applied to all table border lines
horizontalSpacingUiSpacingPadding applied to the left and right of each cell
verticalSpacingUiSpacingPadding applied to the top and bottom of each cell
captionstringAccessible table caption text
captionSide'top' | 'bottom''bottom'Which edge the caption renders on
layout'auto' | 'fixed''auto'CSS table-layout algorithm. 'fixed' sizes columns from the first row and renders faster for large tables; pair with explicit column width styles for full control.
selectablebooleanfalseEnables a checkbox column and row selection state
rowKeystringRow object key used as a unique identifier for selection tracking. Defaults to row object reference — safe when data is a static prop.
emptyLabelstring'No results found'Message shown when no rows match the filter

DataTableColumn

FieldTypeDescription
keystringObject key to read from each row
labelstringColumn header text
sortablebooleanEnable click-to-sort on this column header
align'left' | 'center' | 'right'Text alignment for both header and cells
widthnumber | stringFixed column width — pixel number or any CSS string (e.g. '20%'). Most predictable with layout="fixed".

Custom events

EventDetailDescription
dv-row-select{ keys: unknown[], rows: Record<string, unknown>[] }Fires when selection changes. keys are the rowKey values (or row object references); rows are the full matching row objects.