Data Table

A Data Table is a dynamic table-like UI component designed to present and manipulate structured data. It supports features such as sorting, filtering, pagination, and grouping, enabling users to explore and interact with data efficiently. Data Table should not be confused with a Table, which has very limited functionality.


Utilizes TanStack Table to build and render the DataGrid. Please reference the TanStack Table documentation for more information on expanding the Data Table functionality. There is no web component alternative.

The examples provided in this documentation utilize a consistent data structure to demonstrate the various features of the Data Table component. The data is structured as follows:

type AssetCareRecord = {
id: string,
device: string,
name: string,
status: string,
status_label: string
}
type AssetCareParentRecord = {
id: string,
device: string,
group?: boolean,
subRows?: AssetCareRecord[]
}

Use the enableRowSelection attribute to enable one or more rows in the Data Table to be selected using a checkbox. The data provided to the Data Table in this example follows the shape defined by the AssetCareRecord type.

Cell renderers are used to format the “Devices” and “Status” columns. Sorting has been enabled using the enableSorting attribute and custom sorting functions defined for the relevant columns.

This example demonstrates how to implement pagination in a Data Table using the enablePagination attribute. It includes features such as navigating between pages, selecting the number of rows per page, and displaying the current page information.

This example demonstrates the use of a custom cell renderer that adds an actions menu to each row in the Data Table. The actions menu provides options for interacting with the data in that row.

Use the enableExpanding attribute to enable one or more rows in the Data Table to be selected using a checkbox. The data provided to the Data Table in this example follows the shape defined by the AssetCareParentRecord type.

You can create custom cell renderers to format the data in a cell. Below are two examples of custom cell renderers uses by the Data Tables above.

devices-cell-renderer.tsx
import { Row, Cell } from '@tanstack/react-table';
type CellRenderer = {
cell?: Cell<any, unknown>;
row?: Row<any>;
}
// For demo purposes only - normally you would import these styles from a CSS/SCSS file
const css = `
.devices-expanded-cell {
display: flex;
align-items: center;
gap: var(--ods-sys-space-8);
font-weight: var(--ods-sys-font-weight-semibold);
}
.devices-collapsed-cell {
font-weight: var(--ods-sys-font-weight-semibold);
}
`
export const DevicesCellRenderer = ({ row, cell }: CellRenderer) => {
if (!row?.original.subRows) {
return (
<div>
<div className='devices-expanded-cell'>
{row?.original.device}
</div>
<div>
{row?.original.id}
</div>
<style>
{css}
</style>
</div>
)
}
return (
<>
<style>
{css}
</style>
<span className='devices-collapsed-cell'>
{cell?.getContext().getValue() as string}
</span>
</>
);
}
status-cell-renderer.tsx
import { OdsTag } from '@ods/components/react.tag';
import { OdsIcon } from '@ods/components/react.icon';
import { Row, Cell } from '@tanstack/react-table';
// For demo purposes only - normally you would import these styles from a CSS/SCSS file
const css = `
.status-container {
display: flex;
align-items: center;
gap: var(--ods-sys-space-8);
}
`
type CellRenderer = {
cell?: Cell<any, unknown>;
row?: Row<any>;
}
export const StatusCellRenderer = ({ row, cell }: CellRenderer) => {
const statusMap = {
'washing': <OdsTag variant="success"><OdsIcon className="text-md" name="droplet"></OdsIcon></OdsTag>,
'drying': <OdsTag variant='primary' size='small'><OdsIcon className="text-md" name="droplet"></OdsIcon></OdsTag>
}
if (row?.original.subRows) {
return;
}
return (
<>
<style>
{css}
</style>
<div className='status-container'>{statusMap['washing']} {row?.original.status_label}</div>
</>
)
}
actions-cell-renderer.tsx
import { OdsIconButton } from '@ods/components/react.icon-button';
import { Row, Cell } from '@tanstack/react-table';
type CellRenderer = {
cell?: Cell<any, unknown>;
row?: Row<any>;
callback?: (row: Row<any> | any) => void;
}
// For demo purposes only - normally you would import these styles from a CSS/SCSS file
const css = `
.data-table__action-button-container {
display: flex;
justify-content: center;
}
#data-table__icon-button::part(base) {
color: var(--ods-sys-color-accent);
}
`
export const ActionsCellRenderer = ({ row, cell, callback }: CellRenderer) => {
console.log('row', row);
console.log('cell', cell);
function onClickHandler(event: React.MouseEvent): void {
event.stopPropagation();
if (callback) {
callback(row);
}
}
return (
<div className='data-table__action-button-container'>
<style>
{css}
</style>
{!row?.original.group ? <OdsIconButton id='data-table__icon-button' variant="ghost" name="chevron-right" size='small' onClick={onClickHandler}></OdsIconButton> : null}
</div>
)
}
actions-cell-renderer.tsx
import { OdsDropdown } from '@ods/components/react.dropdown';
import { OdsDivider } from '@ods/components/react.divider';
import { OdsIconButton } from '@ods/components/react.icon-button';
import { OdsMenu, OdsSelectEvent } from '@ods/components/react.menu';
import { OdsMenuItem } from '@ods/components/react.menu-item';
import { Row, Cell } from '@tanstack/react-table';
type CellRenderer = {
cell?: Cell<any, unknown>;
row?: Row<any>;
callback?: (row: Row<any> | any, selectedItem: any) => void;
}
export const ActionsMenuCellRenderer = ({ row, callback }: CellRenderer) => {
function handleSelect(event: OdsSelectEvent & { detail: { item: any } }) {
const selectedItem = event.detail.item;
if (callback) {
callback(row, selectedItem);
}
}
return (
<div>
<OdsDropdown>
<OdsIconButton slot="trigger" variant="ghost" name="more-horiz" size='small'></OdsIconButton>
<OdsMenu onOdsSelect={handleSelect}>
<OdsMenuItem value='view'>View</OdsMenuItem>
<OdsMenuItem value='edit'>Edit</OdsMenuItem>
<OdsDivider></OdsDivider>
<OdsMenuItem value='delete'>Delete</OdsMenuItem>
</OdsMenu>
</OdsDropdown>
</div>
)
}

Usage

This section includes guidelines for designers and developers about the usage of this component in different contexts.

Search