# @fluentui/react-table This package contains two high level components and their subcomponents. ## Table This component is considered **low-level** and should be used when there is a need for more **customization** and support for **non-standard features**. Please check out the **DataGrid component** if you don't need lots of customization and rely on common features. There is less work involved and you will benefit from first class Microsoft design and accessibility support. A Table displays sets of two-dimensional data. The primitive components can be fully customized to support different feature sets. The library provides a default `useTableFeatures` hook that handles the business logic and state management of common features. There is no obligation to use our hook with these components, we've created it for convenience. The `useTableFeatures` hook was designed with feature composition in mind. This means that they are composed using plugins hooks such as `useTableSort` and `useTableSelection` as a part of `useTableFeatures`. This means that as the feature set expands, users will not need to pay the bundle size price for features that they do not intend to use. Please consult the usage examples below for more details. ### Example without interactive features ```tsx import * as React from 'react'; import { FolderRegular, EditRegular, OpenRegular, DocumentRegular, PeopleRegular, DocumentPdfRegular, VideoRegular, } from '@fluentui/react-icons'; import { TableBody, TableCell, TableRow, Table, TableHeader, TableHeaderCell, TableCellLayout, PresenceBadgeStatus, Avatar, } from '@fluentui/react-components'; const items = [ { file: { label: 'Meeting notes', icon: }, author: { label: 'Max Mustermann', status: 'available' }, lastUpdated: { label: '7h ago', timestamp: 1 }, lastUpdate: { label: 'You edited this', icon: , }, }, { file: { label: 'Thursday presentation', icon: }, author: { label: 'Erika Mustermann', status: 'busy' }, lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, lastUpdate: { label: 'You recently opened this', icon: , }, }, { file: { label: 'Training recording', icon: }, author: { label: 'John Doe', status: 'away' }, lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, lastUpdate: { label: 'You recently opened this', icon: , }, }, { file: { label: 'Purchase order', icon: }, author: { label: 'Jane Doe', status: 'offline' }, lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, lastUpdate: { label: 'You shared this in a Teams chat', icon: , }, }, ]; const columns = [ { columnKey: 'file', label: 'File' }, { columnKey: 'author', label: 'Author' }, { columnKey: 'lastUpdated', label: 'Last updated' }, { columnKey: 'lastUpdate', label: 'Last update' }, ]; export const Default = () => { return ( {columns.map(column => ( {column.label} ))} {items.map(item => ( {item.file.label} } > {item.author.label} {item.lastUpdated.label} {item.lastUpdate.label} ))}
); }; ``` ### Example with interactive features ```tsx import * as React from 'react'; import { FolderRegular, EditRegular, OpenRegular, DocumentRegular, PeopleRegular, DocumentPdfRegular, VideoRegular, } from '@fluentui/react-icons'; import { TableBody, TableCell, TableRow, Table, TableHeader, TableHeaderCell, TableSelectionCell, TableCellLayout, useTableFeatures, TableColumnDefinition, useTableSelection, useTableSort, createTableColumn, TableColumnId, PresenceBadgeStatus, Avatar, useArrowNavigationGroup, } from '@fluentui/react-components'; type FileCell = { label: string; icon: JSX.Element; }; type LastUpdatedCell = { label: string; timestamp: number; }; type LastUpdateCell = { label: string; icon: JSX.Element; }; type AuthorCell = { label: string; status: PresenceBadgeStatus; }; type Item = { file: FileCell; author: AuthorCell; lastUpdated: LastUpdatedCell; lastUpdate: LastUpdateCell; }; const items: Item[] = [ { file: { label: 'Meeting notes', icon: }, author: { label: 'Max Mustermann', status: 'available' }, lastUpdated: { label: '7h ago', timestamp: 3 }, lastUpdate: { label: 'You edited this', icon: , }, }, { file: { label: 'Thursday presentation', icon: }, author: { label: 'Erika Mustermann', status: 'busy' }, lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, lastUpdate: { label: 'You recently opened this', icon: , }, }, { file: { label: 'Training recording', icon: }, author: { label: 'John Doe', status: 'away' }, lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, lastUpdate: { label: 'You recently opened this', icon: , }, }, { file: { label: 'Purchase order', icon: }, author: { label: 'Jane Doe', status: 'offline' }, lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 1 }, lastUpdate: { label: 'You shared this in a Teams chat', icon: , }, }, ]; const columns: TableColumnDefinition[] = [ createTableColumn({ columnId: 'file', compare: (a, b) => { return a.file.label.localeCompare(b.file.label); }, }), createTableColumn({ columnId: 'author', compare: (a, b) => { return a.author.label.localeCompare(b.author.label); }, }), createTableColumn({ columnId: 'lastUpdated', compare: (a, b) => { return a.lastUpdated.timestamp - b.lastUpdated.timestamp; }, }), createTableColumn({ columnId: 'lastUpdate', compare: (a, b) => { return a.lastUpdate.label.localeCompare(b.lastUpdate.label); }, }), ]; export const DataGrid = () => { const { getRows, selection: { allRowsSelected, someRowsSelected, toggleAllRows, toggleRow, isRowSelected }, sort: { getSortDirection, toggleColumnSort, sort }, } = useTableFeatures( { columns, items, }, [ useTableSelection({ selectionMode: 'multiselect', defaultSelectedItems: new Set([0, 1]), }), useTableSort({ defaultSortState: { sortColumn: 'file', sortDirection: 'ascending' } }), ], ); const rows = sort( getRows(row => { const selected = isRowSelected(row.rowId); return { ...row, onClick: (e: React.MouseEvent) => toggleRow(e, row.rowId), onKeyDown: (e: React.KeyboardEvent) => { if (e.key === ' ') { e.preventDefault(); toggleRow(e, row.rowId); } }, selected, appearance: selected ? ('brand' as const) : ('none' as const), }; }), ); const headerSortProps = (columnId: TableColumnId) => ({ onClick: (e: React.MouseEvent) => { toggleColumnSort(e, columnId); }, sortDirection: getSortDirection(columnId), }); const keyboardNavAttr = useArrowNavigationGroup({ axis: 'grid' }); return ( File Author Last updated Last update {rows.map(({ item, selected, onClick, onKeyDown, appearance }) => ( {item.file.label} } > {item.author.label} {item.lastUpdated.label} {item.lastUpdate.label} ))}
); }; ``` ## DataGrid This component is a higher level extension of the `Table` primitive components and the `useTableFeatures` hook. `DataGrid` is a feature-rich component that uses `useTableFeatures` internally, so there should always be full feature parity with what can be achieved with primitives. This component is **opinionated** and this is intentional. If the desired scenario can be achieved easily and does not vary too much from documented examples, it can be very convenient. If the desired scenario varies a lot from the documented examples please use the `Table` components with `useTableFeatures` (or another state management solution of choice). ### Example usage ```tsx import * as React from 'react'; import { FolderRegular, EditRegular, OpenRegular, DocumentRegular, PeopleRegular, DocumentPdfRegular, VideoRegular, } from '@fluentui/react-icons'; import { PresenceBadgeStatus, Avatar, DataGridBody, DataGridRow, DataGrid, DataGridHeader, DataGridHeaderCell, DataGridCell, TableCellLayout, TableColumnDefinition, createTableColumn, } from '@fluentui/react-components'; type FileCell = { label: string; icon: JSX.Element; }; type LastUpdatedCell = { label: string; timestamp: number; }; type LastUpdateCell = { label: string; icon: JSX.Element; }; type AuthorCell = { label: string; status: PresenceBadgeStatus; }; type Item = { file: FileCell; author: AuthorCell; lastUpdated: LastUpdatedCell; lastUpdate: LastUpdateCell; }; const items: Item[] = [ { file: { label: 'Meeting notes', icon: }, author: { label: 'Max Mustermann', status: 'available' }, lastUpdated: { label: '7h ago', timestamp: 1 }, lastUpdate: { label: 'You edited this', icon: , }, }, { file: { label: 'Thursday presentation', icon: }, author: { label: 'Erika Mustermann', status: 'busy' }, lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, lastUpdate: { label: 'You recently opened this', icon: , }, }, { file: { label: 'Training recording', icon: }, author: { label: 'John Doe', status: 'away' }, lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, lastUpdate: { label: 'You recently opened this', icon: , }, }, { file: { label: 'Purchase order', icon: }, author: { label: 'Jane Doe', status: 'offline' }, lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, lastUpdate: { label: 'You shared this in a Teams chat', icon: , }, }, ]; const columns: TableColumnDefinition[] = [ createTableColumn({ columnId: 'file', compare: (a, b) => { return a.file.label.localeCompare(b.file.label); }, renderHeaderCell: () => { return 'File'; }, renderCell: item => { return {item.file.label}; }, }), createTableColumn({ columnId: 'author', compare: (a, b) => { return a.author.label.localeCompare(b.author.label); }, renderHeaderCell: () => { return 'Author'; }, renderCell: item => { return ( } > {item.author.label} ); }, }), createTableColumn({ columnId: 'lastUpdated', compare: (a, b) => { return a.lastUpdated.timestamp - b.lastUpdated.timestamp; }, renderHeaderCell: () => { return 'Last updated'; }, renderCell: item => { return item.lastUpdated.label; }, }), createTableColumn({ columnId: 'lastUpdate', compare: (a, b) => { return a.lastUpdate.label.localeCompare(b.lastUpdate.label); }, renderHeaderCell: () => { return 'Last update'; }, renderCell: item => { return {item.lastUpdate.label}; }, }), ]; export const Default = () => { return ( item.file.label} onSelectionChange={(e, data) => console.log(data)} > {({ renderHeaderCell }) => {renderHeaderCell()}} > {({ item, rowId }) => ( key={rowId} selectionCell={{ 'aria-label': 'Select row' }}> {({ renderCell }) => {renderCell(item)}} )} ); }; ```