Import
import { Table } from '@contentful/f36-components';// orimport { Table } from '@contentful/f36-table';
Examples
Basic usage
function TableBasicUsageExample() {return (<Table><Table.Head><Table.Row><Table.Cell>Name</Table.Cell><Table.Cell>Email</Table.Cell><Table.Cell>Organization role</Table.Cell><Table.Cell>Last activity</Table.Cell></Table.Row></Table.Head><Table.Body><Table.Row><Table.Cell>Claus Mitchell</Table.Cell><Table.Cell>claus.mitchell@contentful.com</Table.Cell><Table.Cell>CEO</Table.Cell><Table.Cell>August 29, 2018</Table.Cell></Table.Row><Table.Row><Table.Cell>Johannes Ramos</Table.Cell><Table.Cell>johannes.ramos@contentful.com</Table.Cell><Table.Cell>CTO</Table.Cell><Table.Cell>July 27, 2019</Table.Cell></Table.Row><Table.Row><Table.Cell>Alex Kalinoski</Table.Cell><Table.Cell>alex.kalinoski@contentful.com</Table.Cell><Table.Cell>CDO</Table.Cell><Table.Cell>June 13, 2019</Table.Cell></Table.Row></Table.Body></Table>);}
Dynamic creation
One very common use case for a table is that you will have a set of data and you would like to show a table row for each item in that set.
To achieve that result, you can iterate over the data and create Table.Row and Table.Cell for each item:
function TableDynamicCreation() {const contentTypes = [{id: '1',name: 'Category',description:'Categories can be applied to Courses and Lessons. Assigning Multiple categories is also possible.',updatedAt: 'Nov 15, 2021',status: 'published',},{id: '2',updatedAt: 'Nov 15, 2021',status: 'draft',},{id: '3',name: 'Layout',description:'A page consisting of freely configurable and rearrangeable content modules.',updatedAt: 'Nov 15, 2021',status: 'published',},];return (<Table><Table.Head><Table.Row><Table.Cell>Name</Table.Cell><Table.Cell>Description</Table.Cell><Table.Cell>Updated</Table.Cell><Table.Cell>Status</Table.Cell></Table.Row></Table.Head><Table.Body>{contentTypes.map((contentType) => {return (<Table.Row key={contentType.id}><Table.Cell>{contentType.name || 'Untitled'}</Table.Cell><Table.Cell>{contentType.description}</Table.Cell><Table.Cell>{contentType.updatedAt}</Table.Cell><Table.Cell><Badgevariant={contentType.status === 'published' ? 'positive' : 'warning'}>{contentType.status}</Badge></Table.Cell></Table.Row>);})}</Table.Body></Table>);}
With sorting
Table cells in the table header can be marked as sortable and sorted either in ascending or descending order.
function TableWithSorting() {const contentTypes = [{id: '1',name: 'Category',description:'Categories can be applied to Courses and Lessons. Assigning Multiple categories is also possible.',updatedAt: 'Nov 1, 2021',status: 'published',},{id: '2',updatedAt: 'Nov 11, 2021',status: 'draft',},{id: '3',name: 'Layout',description:'A page consisting of freely configurable and rearrangeable content modules.',updatedAt: 'Nov 18, 2021',status: 'published',},];const [sorting, setSorting] = useState(undefined);const [sortedRows, setSortedRows] = useState(contentTypes);const handleSort = ({ column }) => {const direction =sorting && sorting.column === column? sorting.direction === TableCellSorting.Ascending? TableCellSorting.Descending: TableCellSorting.Ascending: TableCellSorting.Ascending;setSortedRows((rows) => {const sorted = rows.sort((rowA, rowB) => {let a = rowA[column];const b = rowB[column];if (column === 'name') {a = rowA[column] || 'Untitled';}return a.localeCompare(b);});return direction === TableCellSorting.Ascending? sorted: sorted.reverse();});setSorting({ column, direction });};return (<Table><Table.Head><Table.Row><Table.CellisSortableonClick={() => handleSort({ column: 'name' })}sortDirection={sorting && sorting.column === 'name' ? sorting.direction : false}>Name</Table.Cell><Table.Cell>Description</Table.Cell><Table.CellisSortableonClick={() => handleSort({ column: 'updatedAt' })}sortDirection={sorting && sorting.column === 'updatedAt'? sorting.direction: false}>Updated</Table.Cell><Table.Cell>Status</Table.Cell></Table.Row></Table.Head><Table.Body>{sortedRows.map((contentType) => {return (<Table.Row key={contentType.id}><Table.Cell>{contentType.name || 'Untitled'}</Table.Cell><Table.Cell>{contentType.description}</Table.Cell><Table.Cell>{contentType.updatedAt}</Table.Cell><Table.Cell><Badgevariant={contentType.status === 'published' ? 'positive' : 'warning'}>{contentType.status}</Badge></Table.Cell></Table.Row>);})}</Table.Body></Table>);}
Props (API reference)
Open in StorybookTable
Name | Type | Default |
|---|---|---|
| className | string CSS class to be appended to the root element | |
| css | string number false true ComponentSelector Keyframes SerializedStyles ArrayInterpolation<undefined> ObjectInterpolation<undefined> (theme: any) => Interpolation<undefined> | |
| layout | "inline" "embedded" | inline |
| testId | string A [data-test-id] attribute used for testing purposes | cf-ui-table |
| verticalAlign | "baseline" "bottom" "middle" "top" | top |
Table.Head
Name | Type | Default |
|---|---|---|
| children required | ReactNode | |
| className | string CSS class to be appended to the root element | |
| css | string number false true ComponentSelector Keyframes SerializedStyles ArrayInterpolation<undefined> ObjectInterpolation<undefined> (theme: any) => Interpolation<undefined> | |
| isSticky | false true | false |
| offsetTop | string number | |
| testId | string A [data-test-id] attribute used for testing purposes | cf-ui-table-head |
Table.Body
Name | Type | Default |
|---|---|---|
| children required | ReactNode | |
| className | string CSS class to be appended to the root element | |
| css | string number false true ComponentSelector Keyframes SerializedStyles ArrayInterpolation<undefined> ObjectInterpolation<undefined> (theme: any) => Interpolation<undefined> | |
| testId | string A [data-test-id] attribute used for testing purposes |
Table.Row
Name | Type | Default |
|---|---|---|
| children required | ReactNode | |
| className | string CSS class to be appended to the root element | |
| css | string number false true ComponentSelector Keyframes SerializedStyles ArrayInterpolation<undefined> ObjectInterpolation<undefined> (theme: any) => Interpolation<undefined> | |
| isSelected | false true | false |
| testId | string A [data-test-id] attribute used for testing purposes | cf-ui-table-row |
Table.Cell
Name | Type | Default |
|---|---|---|
| align | "left" "center" "right" | |
| as | HTML Tag or React Component (e.g. div, span, etc) | |
| children | ReactNode | |
| className | string CSS class to be appended to the root element | |
| isSortable | false true | |
| isTruncated | false true | |
| isWordBreak | false true | |
| sortButtonAriaLabel | string Aria label for the sort button when isSortable is set | |
| sortDirection | "ascending" "descending" | |
| testId | string A [data-test-id] attribute used for testing purposes | |
| width | string number |
Content guidelines
- Keep headers short
- Headers should be informative and descriptive
- Content in the table should be concise and scannable
Accessibility
- It will render tabular data using the native HTML element
tablewhich is recommended.