Skip to main content

DataTable - Data

Displays a matrix of information with columns, rows, and information that can operate dynamically.

Submit feedback
github
import { DataTable } from '@uhg-abyss/web/ui/DataTable';
import { useDataTable } from '@uhg-abyss/web/hooks/useDataTable';

Initial columns and data

The initialColumns property specifies the columns to display in the table on the first render. It accepts an array of objects, each of which must contain the header and accessorKey values.

{
header: string;
accessorKey: string;
}

The initialData property determines the entries to display in the table on the first render. It accepts an array of objects, where each object represents a row. Each row must have a unique identifier field. By default, the table expects this field to be named uniqueId, but you can specify a different field name using the rowIdKey prop.

{
uniqueId: string; // Default identifier field
[accessorKey: string]: any; // Other properties can be added as needed
}

Here is an example using the default uniqueId field:

[
{
uniqueId: '1dc47178-a614-4fcf-8511-ae05bc9bf511',
col1: 'Col 1/Row 1',
col2: '12/31/2022',
col3: 0,
col4: 'Completed',
},
{
uniqueId: '4109763d-9cea-4cbc-8a17-973b01c484e2',
col1: 'Col 1/Row 2',
col2: '1/1/2023',
col3: 1,
col4: 'In Progress',
},
];

Using a custom ID field

If your data uses a different field name for the unique identifier, specify it with the rowIdKey prop:

// Data with custom ID field
const data = [
{ applicationGuid: 'abc-123', col1: 'Row 1', col2: 'Data' },
{ applicationGuid: 'def-456', col1: 'Row 2', col2: 'Data' },
];
const dataTableProps = useDataTable({
initialData: data,
initialColumns: columns,
rowIdKey: 'applicationGuid', // Specify your custom ID field
});

Note: When using TypeScript, rowIdKey is automatically required if your data type lacks a uniqueId field. This compile-time enforcement prevents configuration errors. See Types documentation for details.

Why row identifiers matter

The unique identifier field (whether uniqueId or a custom field via rowIdKey) is critical for DataTable to efficiently track and manage row state. It's used for:

Direct features:

Behind the scenes:

If using data from a remote API, ensure your back-end provides a stable unique identifier for each row.

Basic example

Use the initialData and initialColumns in combination to set the initial state of your DataTable.

Updating data

Use the setColumns and setData methods to update the columns and rows in the table. Do not mutate initial state data as a way to update data on the client side.

Note: These methods are not compatible with server-side pagination.

A second parameter of type boolean can be passed to setColumns and setData to skip page reset; the default is false.

  • Note: If you click "Update Data (Skip Page Reset)", you will see an issue with it staying on a blank page.
  • Reason: Skipping the page reset can cause the table to display outdated or incorrect data, leading to potential issues with data consistency and user experience.

Data defaults and overrides

By default, `DataTableautomatically left-aligns all values.

Teams can oveDataTablebehavior on a per-column basis by using the column definition's meta property and providing a custom textAlign value:

If you want to turn a column into a row header, pass the isRowHeader: true prop to an individual column meta property.

{
header: 'Column 1',
accessorKey: 'col1',
meta: {
textAlign: 'center', // 'left' | 'right' | 'center'
isRowHeader: true,
},
},

Downloading data

The DataTable.DownloadDropdown sub-component provides a dropdown menu for downloading data from the table. It can be used to export data in CSV format, and it can be customized with various download options.

<DataTable.DownloadDropdown />

Standard export options

Abyss has three built-in export options:

  • 'exportAllData' - Exports all data in the table.
  • 'exportVisibleData' - Exports all visible data displayed. If using pagination, it will export only the current page.
  • 'exportFilteredData' - Exports data with sorting and filtering rules applied. If using pagination, it will export all pages.
const dropdownMenuItems = [
{
title: 'Example Data',
onClick: 'exportAllData', // 'exportAllData' | 'exportVisibleData' | 'exportFilteredData'
csvFilename: 'example_data.csv',
icon: <IconSymbol icon="example_icon" />,
},
];
<DataTable.DownloadDropdown dropdownMenuItems={dropdownMenuItems} />;

Note:

Refer to the Custom download options section below to learn more about advanced export configuration.

Remove CSV columns

Use the removeCsvColumns prop to remove columns from the built-in export options. This prop accepts an array containing the accessorKey values from the columns you would like removed.

Note: Predefined columns such as the row reordering handle, row selection checkboxes, individual action buttons, etc. will be removed by default.

<DataTable.DownloadDropdown
removeCsvColumns={['col1', 'col3']}
dropdownMenuItems={dropdownMenuItems}
/>

Custom CSV cell

The customSetCellCsv property is a function that returns the cell value (within a value property) when downloading the table data CSV file. Use this whenever you're performing any custom rendering within the cell to ensure the data is also properly rendered within the CSV.

const renderColData = (value) => {
const { colName, rowName } = value;
return `${colName} / ${rowName}`;
};
{
header: 'Column 1',
accessorKey: 'col1',
cell: (props) => {
const value = props.getValue();
const renderedValue = renderColData(value);
return renderedValue;
},
meta: {
customSetCellCsv: ({ value }) => {
return renderColData(value);
},
},
},

Download the CSV file example below to see the use case of prop and how the column without customSetCellCsv attempts to render the full object.

Custom download options

Teams looking for anything more advanced than the basic exports should be looking at this section. Teams are free to export the data however they see fit. One option is to use the downloadCsv utility from @uhg-abyss/web/tools/downloadCsv.

To create a custom download option, provide a function to the menu item's onClick property. The handler receives the table instance for advanced exports.

Note: Using a custom function means that you will be responsible for handling the data export logic. This means the csvFilename and removeCsvColumns props are not applicable.

const dropdownMenuItem = {
title: 'Custom Export Example',
onClick: (tableInstance) => {
// Use the tableInstance to access the current state of the table, including selected rows, columns, filters, etc.
downloadCsv({
columns: //...,
data: //...,
filename: 'custom-download-csv',
});
},
icon: <IconSymbol icon="download_2" />,
};

This example below uses downloadCsv to generate a CSV and the jsPDF library to generate a PDF. Try selecting some rows and then clicking the "Custom Export PDF" / "Custom CSV Export" option in the download dropdown to see how it works!

Disclaimer: The PDF generated is not accessible and is just a simple example of what can be done. Teams looking to implement a PDF export should work with their accessibility teams to ensure the generated file meets accessibility standards.

Component Tokens

Note: Click on the token row to copy the token to your clipboard.

DataTable Tokens

Token NameValue
data-table.color.border.column-header.drag
#002677
data-table.color.border.root
#CBCCCD
data-table.color.border.row.drag
#002677
data-table.color.border.table
#CBCCCD
data-table.color.icon.column-header-menus.grouping.active
#002677
data-table.color.icon.column-header-menus.grouping.hover
#004BA0
data-table.color.icon.column-header-menus.grouping.rest
#196ECF
data-table.color.icon.column-header-menus.sorting.active
#002677
data-table.color.icon.column-header-menus.sorting.hover
#004BA0
data-table.color.icon.column-header-menus.sorting.rest
#196ECF
data-table.color.icon.drag-handle.active
#002677
data-table.color.icon.drag-handle.hover
#004BA0
data-table.color.icon.drag-handle.rest
#196ECF
data-table.color.icon.expander.active
#002677
data-table.color.icon.expander.disabled
#7D7F81
data-table.color.icon.expander.hover
#004BA0
data-table.color.icon.expander.rest
#196ECF
data-table.color.icon.utility.drag-alternative.active
#000000
data-table.color.icon.utility.drag-alternative.disabled
#7D7F81
data-table.color.icon.utility.drag-alternative.hover
#323334
data-table.color.icon.utility.drag-alternative.rest
#4B4D4F
data-table.color.icon.utility.filter.active
#002677
data-table.color.icon.utility.filter.hover
#004BA0
data-table.color.icon.utility.filter.rest
#196ECF
data-table.color.surface.column-header.active
#E5F8FB
data-table.color.surface.column-header.default
#F3F3F3
data-table.color.surface.column-header.drag
#E5F8FB
data-table.color.surface.footer
#F3F3F3
data-table.color.surface.header
#FFFFFF
data-table.color.surface.root
#FFFFFF
data-table.color.surface.row.drag
#E5F8FB
data-table.color.surface.row.even
#FAFCFF
data-table.color.surface.row.highlighted
#E5F8FB
data-table.color.surface.row.hover
#F3F3F3
data-table.color.surface.row.odd
#FFFFFF
data-table.color.surface.table
#FFFFFF
data-table.color.text.cell
#4B4D4F
data-table.color.text.column-header
#4B4D4F
data-table.color.text.header.heading
#002677
data-table.color.text.header.paragraph
#4B4D4F
data-table.border-radius.all.container
8px
data-table.border-width.all.column-header.drag
2px
data-table.border-width.all.root
1px
data-table.border-width.all.row.drag
2px
data-table.border-width.all.table
1px
data-table.sizing.all.icon.column-header-menus
20px
data-table.sizing.all.icon.drag-handle-row
24px
data-table.sizing.all.icon.expander-column
24px
data-table.sizing.all.icon.utility.drag-alternative
20px
data-table.sizing.all.icon.utility.filter
20px
data-table.sizing.height.cell.comfortable
48px
data-table.sizing.height.cell.compact
32px
data-table.sizing.height.cell.cozy
40px
data-table.spacing.gap.horizontal.button-group
8px
data-table.spacing.gap.horizontal.cell
4px
data-table.spacing.gap.horizontal.drag-alternative
8px
data-table.spacing.gap.horizontal.input-container
8px
data-table.spacing.gap.horizontal.slot-wrapper
24px
data-table.spacing.gap.vertical.column-header
2px
data-table.spacing.gap.vertical.header
4px
data-table.spacing.gap.filter-two-inputs
16px
data-table.spacing.padding.all.column-header
8px
data-table.spacing.padding.all.column-header-menus
2px
data-table.spacing.padding.all.header
16px
data-table.spacing.padding.all.result-text
16px
data-table.spacing.padding.all.slot-wrapper
16px
data-table.spacing.padding.horizontal.cell
8px
data-table.spacing.padding.vertical.button-group
8px
data-table.spacing.padding.vertical.cell
4px
data-table.elevation.column.pinned.left
6px 0px 8px -2px rgba(0,0,0,0.16)
data-table.elevation.column.pinned.right
-6px 0px 8px -2px rgba(0,0,0,0.16)
data-table.elevation.column-header
0px 6px 8px -2px rgba(0,0,0,0.16)
data-table.elevation.table-settings-dropdown.section-header
0px 2px 4px -2px rgba(0,0,0,0.16)

Table of Contents