import { DataTable } from '@uhg-abyss/web/ui/DataTable';import { useDataTable } from '@uhg-abyss/web/hooks/useDataTable';There are three different types of expansion available:
'subRows': This mode allows you to expand rows to show additional, nested sub-rows. This is useful for displaying hierarchical data or related information.'subComponent': This mode allows you to expand rows to show a custom sub-component. This is useful for displaying detailed information or custom content related to the row.'grouping': This mode allows you to expand rows to show grouped data. This is useful for displaying aggregated information.
Note: The expandColumnConfig.expandMode property only needs to be set for 'subRows' and 'subComponent'. Grouping is enabled and managed via tableConfig.
Sub-rows
Sub-row expansion allows rows to expand to show additional, nested sub-rows. To enable it, set expandColumnConfig.expandMode to 'subRows'.
const dataTableProps = useDataTable({ // ... expandColumnConfig: { expandMode: 'subRows', }, // ...});Disclaimer: Features such as row drag-and-drop will not be compatible with sub-row expansion.
Programmatically expanding sub-rows
To manage the expansion state, provide a function to the tableConfig.onExpandedChange property and set the state.expanded property; we recommend using useState for this, as shown below.
const [expanded, setExpanded] = useState({});
const dataTableProps = useDataTable({ // ... expandColumnConfig: { expandMode: 'subRows', }, tableConfig: { onExpandedChange: setExpanded, state: { expanded, }, }, // ...});Filtering sub-rows
To enable filtering on sub-rows, set up filtering as normal and set tableConfig.filterFromLeafRows to true.
const dataTableProps = useDataTable({ // ... tableConfig: { filterFromLeafRows: true, }, // ...});Paginating sub-rows
By default, expanded rows are considered separate for the purposes of pagination; that is, if a row is expanded to show enough rows that there are more than the current page size, the other rows will be pushed to the next page. To prevent this behavior and to always show sub-rows on the same page as their parent, set tableConfig.paginateExpandedRows to false.
const dataTableProps = useDataTable({ // ... tableConfig: { paginateExpandedRows: false, }, // ...});Sub-component
Sub-component expansion allows rows to expand to show a custom sub-component. To enable it, set expandColumnConfig.expandMode to 'subComponent' and provide the custom sub-component to expandColumnConfig.renderSubComponent. The renderSubComponent function receives the row object as a prop, which contains the data for the row being expanded.
The sub-component also requires a fixed height. Use the expandColumnConfig.subComponentHeight property to set this height. In the example below, the component is 50px tall, but the subComponentHeight is 100px; the extra space is used for padding.
const renderSubComponent = ({ row }) => { const { col1, col2, col3, col4 } = row.original; const content = `On ${col2}, "${col1}" had ${col3} instances and was marked as ${col4}.`; return ( <div style={{ height: '100%', width: '100%', alignContent: 'center' }}> {content} </div> );};
const dataTableProps = useDataTable({ // ... expandColumnConfig: { expandMode: 'subComponent', renderSubComponent, subComponentHeight: 100, }, // ...});For accessibility purposes, you will also need to define which column best labels the contents of its row. This changes cells in that column from <th> to <th scope="row"> to help screen reader users more clearly understand data in that row.
const dataTableProps = useDataTable({ // ... initialColumns: [ { header: 'Name', accessorKey: 'name', meta: { isRowHeader: true, }, }, // ... ], // ...});Programmatically expanding sub-components
As with sub-rows, to manage the expansion state, provide a function to the tableConfig.onExpandedChange property and set the state.expanded property; we recommend using useState for this, as shown below.
const [expanded, setExpanded] = useState({});
const dataTableProps = useDataTable({ // ... expandColumnConfig: { expandMode: 'subComponent', renderSubComponent, subComponentHeight: 100, }, tableConfig: { onExpandedChange: setExpanded, state: { expanded, }, }, // ...});Grouping
Grouping expansion allows rows to be grouped by column values and then expanded to show all rows in the group. It is disabled by default. To enable grouping for all columns, set tableConfig.enableGrouping to true.
const dataTableProps = useDataTable({ // ... tableConfig: { enableGrouping: true, }, // ...});The enableGrouping property can also be provided to individual columns for more granular adjustment.
{ header: 'Column 1', accessorKey: 'col1', enableGrouping: true,}To manage the grouping state, provide a function to the tableConfig.onGroupingChange property and set the state.grouping property; we recommend using useState for this, as shown below.
const [grouping, setGrouping] = useState([]);
const dataTableProps = useDataTable({ // ... tableConfig: { enableGrouping: true, onGroupingChange: setGrouping, state: { grouping, }, }, // ...});Please see the TanStack Table grouping docs for more details and configuration options.
Note: As noted in the TanStack docs above, "There are not currently many easy ways to do server-side grouping with TanStack Table." For this reason, we do not allow server-side grouping in DataTable and grouping cannot be used with server-side operations.
Disclaimer: Features such as row drag-and-drop will not be compatible with grouping.
Paginating grouped rows
By default, expanded rows are considered separate for the purposes of pagination; that is, if a row is expanded to show enough rows that there are more than the current page size, the other rows will be pushed to the next page. To prevent this behavior and to always show grouped rows on the same page as their parent, set tableConfig.paginateExpandedRows to false.
const dataTableProps = useDataTable({ // ... tableConfig: { paginateExpandedRows: false, }, // ...});Component Tokens
Note: Click on the token row to copy the token to your clipboard.
DataTable Tokens
| Token Name | Value | |
|---|---|---|
| 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) |