Skip to Content

Table

Data tables display sets of data.

This page has not yet been finished and is being worked on. In the meantime, you can view the stories.

import * as React from 'react';
import { Table, DefaultCell } from '@itwin/itwinui-react';

export default () => {
  const generateItem = React.useCallback((index, parentRow = '', depth = 0) => {
    const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`;
    const rating = Math.round(Math.random() * 5);
    return {
      product: `Product ${keyValue}`,
      price: ((index % 10) + 1) * 15,
      quantity: ((index % 10) + 1) * 150,
      rating: rating,
      status: rating >= 4 ? 'positive' : rating === 3 ? 'warning' : 'negative',
      subRows:
        depth < 1
          ? Array(Math.round(index % 2))
              .fill(null)
              .map((_, index) => generateItem(index, keyValue, depth + 1))
          : [],
    };
  }, []);

  const data = React.useMemo(
    () =>
      Array(3)
        .fill(null)
        .map((_, index) => generateItem(index)),
    [generateItem],
  );

  const columns = React.useMemo(
    () => [
      {
        id: 'product',
        Header: 'Product',
        accessor: 'product',
        width: '40%',
      },
      {
        id: 'price',
        Header: 'Price',
        accessor: 'price',
        Cell: (props) => {
          return <>${props.value}</>;
        },
      },
      {
        id: 'rating',
        Header: 'Rating',
        accessor: 'rating',
        cellRenderer: (props) => {
          return (
            <DefaultCell
              {...props}
              status={props.cellProps.row.original.status}
            >
              {props.cellProps.row.original.rating}/5
            </DefaultCell>
          );
        },
      },
    ],
    [],
  );

  const rowProps = React.useCallback((row) => {
    return {
      status: row.original.status,
    };
  }, []);

  return (
    <div className='demo-container'>
      <Table
        columns={columns}
        emptyTableContent='No data.'
        data={data}
        rowProps={rowProps}
        density='condensed'
      />
    </div>
  );
};

Tables are an important element in most web-based applications. We’ve presented a set of flexible standards to allow for a variety of table styles. As always, the specifics of how you style your table should be determined by the desired user experience and the goals of the application.

Bentley makes extensive use of tables and data grids throughout its web applications. Use the following flexible grid format below in most circumstances as it provides functionality “built in” to the design, and because users learning how to consistently sort, filter, and search tables is an important skill to leverage.

Props

Prop Description Default
data
Table data list. Must be memoized.
Supports expandable sub-rows using the subRows field in data entries. If some rows don't have sub-data, it is recommended to pass an empty array to subRows for consistent spacing.
T[]
columns
List of columns.
Should not have a top-level Header or a columns sub-property. They are only allowed to be passed for backwards compatibility. See migration guide.
Column<T>[]
initialState
Partial<TableState<T>>
stateReducer
(newState: TableState<T>, action: ActionType, previousState: TableState<T>, instance?: TableInstance<T>) => TableState<...>
useControlledState
(state: TableState<T>, meta: MetaBase<T>) => TableState<T>
defaultColumn
Partial<Column<T>>
getSubRows
(originalRow: T, relativeIndex: number) => T[]
getRowId
(originalRow: T, relativeIndex: number, parent?: Row<T>) => string
autoResetHiddenColumns
boolean
manualRowSelectedKey
string
autoResetSelectedRows
boolean
selectSubRows
boolean
manualExpandedKey
string
paginateExpandedRows
boolean
expandSubRows
boolean
autoResetExpanded
boolean
manualFilters
boolean
disableFilters
boolean
defaultCanFilter
boolean
filterTypes
FilterTypes<T>
autoResetFilters
boolean
pageCount
number
manualPagination
boolean
autoResetPage
boolean
globalFilter
string | ((rows: Row<T>[], columnIds: IdType<T>[], filterValue: any) => Row<T>[])
manualGlobalFilter
boolean
autoResetGlobalFilter
boolean
disableGlobalFilter
boolean
autoResetResize
boolean
manualSortBy
boolean
defaultCanSort
boolean
disableMultiSort
boolean
isMultiSortEvent
(e: MouseEvent<Element, MouseEvent>) => boolean
maxMultiSortColCount
number
disableSortRemove
boolean
disabledMultiRemove
boolean
orderByFn
(rows: Row<T>[], sortFns: OrderByFn<T>[], directions: boolean[]) => Row<T>[]
sortTypes
Record<string, SortByFn<T>>
autoResetSortBy
boolean
columnResizeMode
Column's resize mode. - fit - when resizing it affects current and the next column, e.g. when increasing width of current column, next column's width will decrease. - expand - when resizing it affects only the current column, e.g. when increasing width of the current column, next column's width remains the same.
"fit" | "expand"
'fit'
isLoading
Flag whether data is loading.
boolean
false
emptyTableContent
Content shown when there is no data.
ReactNode
isSelectable
Flag whether table rows can be selectable.
boolean
false
onSelect
Handler for rows selection. Must be memoized. This is triggered only by user initiated actions (i.e. data change will not call it).
(selectedData: T[], tableState?: TableState<T>) => void
onRowClick
Handler for when a row is clicked. Must be memoized.
(event: MouseEvent<Element, MouseEvent>, row: Row<T>) => void
selectionMode
Modify the selection mode of the table. The column with checkboxes will not be present with 'single' selection mode.
"multi" | "single"
'multi'
isSortable
Flag whether table columns can be sortable.
boolean
false
onSort
Callback function when sort changes. Use with manualSortBy to handle sorting yourself e.g. sort in server-side. Must be memoized.
(state: TableState<T>) => void
onBottomReached
Callback function when scroll reaches bottom. Can be used for lazy-loading the data.
() => void
onRowInViewport
Callback function when row is in viewport.
(rowData: T) => void
intersectionMargin
Margin in pixels when row is considered to be already in viewport. Used for onBottomReached and onRowInViewport.
number
300
subComponent
A function that will be used for rendering a component for each row if that row is expanded. Component will be placed right after the row. Can return false/null if row should not be expandable.
(row: Row<T>) => ReactNode
expanderCell
A function used for overriding default expander cell. subComponent must be present. Make sure to trigger cellProps.row.toggleRowExpanded().
(cellProps: CellProps<T>) => ReactNode
onExpand
Handler for row expand events. Will trigger when expanding and collapsing rows.
(expandedData: T[], tableState?: TableState<T>) => void
onFilter
Callback function when filters change. Use with manualFilters to handle filtering yourself e.g. filter in server-side. Must be memoized.
(filters: TableFilterValue<T>[], state: TableState<T>, filteredData?: Row<T>[]) => void
globalFilterValue
Value used for global filtering. Use with globalFilter and/or manualGlobalFilter to handle filtering yourself e.g. filter in server-side. Must be memoized.
unknown
emptyFilteredTableContent
Content shown when there is no data after filtering.
ReactNode
isRowDisabled
Function that should return true if a row is disabled (i.e. cannot be selected or expanded). If not specified, all rows are enabled.
(rowData: T) => boolean
rowProps
Function that should return custom props passed to the each row. Must be memoized.
(row: Row<T>) => Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ...; } & { ...; }
density
Modify the density of the table (adjusts the row height).
"default" | "condensed" | "extra-condensed"
'default'
selectRowOnClick
Flag whether to select a row when clicked anywhere inside of it.
boolean
true
paginatorRenderer
Function that takes TablePaginatorRendererProps as an argument and returns pagination component.
Recommended to use TablePaginator. Passing props to TablePaginator handles all state management and is enough for basic use-cases.
(props: TablePaginatorRendererProps) => ReactNode
pageSize
Number of rows per page.
number
25
isResizable
Flag whether columns are resizable. In order to disable resizing for specific column, set disableResizing: true for that column.
boolean
false
styleType
Style of the table.
"default" | "zebra-rows"
'default'
enableVirtualization
Virtualization is used for the scrollable table body. Height on the table is required for virtualization to work.
boolean
false
enableColumnReordering
Flag whether columns can be reordered.
boolean
false
headerWrapperProps
Passes props to Table header wrapper.
DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
headerProps
Passes props to Table header.
DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
bodyProps
Passes custom props to Table body.
DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
emptyTableContentProps
Passes custom props to empty table.
DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
scrollToRow
Function that returns index of the row that you want to scroll to.
When using with lazy-loading table, you need to take care that row is already loaded. It doesn't work with paginated tables. @beta
(rows: Row<T>[], data: T[]) => number
id
string
className
string
style
CSSProperties