Table
Tables are used to display tabular data using rows and columns. They allow users to quickly scan, sort, compare, and take action on large amounts of data.
Installation
npx nextui-cli@latest add table
The above command is for individual installation only. You may skip this step if @nextui-org/react
is already installed globally.
Import
NextUI exports 6 table-related components:
- Table: The main component to display a table.
- TableHeader: The header of the table.
- TableBody: The body of the table.
- TableColumn: The column of the table.
- TableRow: The row of the table.
- TableCell: The cell of the table.
Usage
Dynamic
To render a table dynamically, you can use the columns
prop to pass the columns and items
prop to pass the data.
Why not array map?
Using the items
prop and providing a render function allows react-aria
to automatically cache the results of rendering each item and avoid re-rendering all items in the
collection when only one of them changes. This has big performance benefits for large
collections.
You could also use Array.map
to render the items, but it will not be as performant as using the items
and columns
prop.
Example:
import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue} from "@nextui-org/react";const rows = [...];const columns = [...];export default function App() {return (<Table aria-label="Example table with dynamic content"><TableHeader>{columns.map((column) =><TableColumn key={column.key}>{column.label}</TableColumn>)}</TableHeader><TableBody>{rows.map((row) =><TableRow key={row.key}>{(columnKey) => <TableCell>{getKeyValue(row, columnKey)}</TableCell>}</TableRow>)}</TableBody></Table>);}
Note: To learn more about React Aria collections and how to use them, please check React Aria Collections.
Empty State
You can use the emptyContent
prop to render a custom component when the table is empty.
Without Header
In case you don't want to render the header, you can use the hideHeader
prop.
Without Wrapper
By default the table is wrapped in a div
element with a small shadow effect and a border radius.
You can use the removeWrapper
prop to remove the wrapper and only render the table.
Custom Cells
You can render any component inside the table cell. In the example below, we are rendering different components according to the key
of the column.
Striped Rows
You can use the isStriped
prop to render striped rows.
Single Row Selection
It is possible to make the table rows selectable. To do so, you can use the selectionMode
prop. Use defaultSelectedKeys
to
provide a default set of selected rows.
Note: The value of the selected keys must match the key prop of the row.
Multiple Row Selection
You can also select multiple rows by using the selectionMode="multiple"
prop. Use defaultSelectedKeys
to
provide a default set of selected rows.
Note: When using multiple selection, selectable checkboxes will be rendered in the first column of the table.
Disallow Empty Selection
Table also supports a disallowEmptySelection
prop which forces the user to have at least one
row in the Table selected at all times. In this mode, if a single row is selected and the
user presses it, it will not be deselected.
Controlled Selection
To programmatically control row selection, use the selectedKeys
prop paired with the onSelectionChange
callback.
The key prop from the selected rows will be passed into the callback when the row is pressed, allowing you to update state accordingly.
Note: The
selectedKeys
property must be aSet
object.
Disabled Rows
You can disable rows by using the disabledKeys
prop. This will prevent rows from being
selectable as shown in the example below.
Selection Behavior
By default, Table uses the toggle
selection behavior, which behaves like a checkbox group:
clicking, tapping, or pressing the Space or Enter keys toggles selection for the focused row.
When the selectionBehavior
prop is set to replace
, clicking a row with the mouse replaces
the selection with only that row. Using the arrow keys moves both focus and selection.
To select multiple rows, modifier keys such as Ctrl, Cmd, and Shift can be used.
Rows Actions
Table supports rows via the onRowAction
callback. In the default toggle
selection
behavior, when nothing is selected, clicking or tapping the row triggers the row action.
This behavior is slightly different in the replace
selection behavior, where single
clicking selects the row and actions are performed via double click.
Sorting Rows
Table supports sorting its data when a column header is pressed. To designate that a Column
should support sorting, provide it with the allowsSorting
prop.
Table accepts a sortDescriptor
prop that defines the current column key to sort by
and the sort direction (ascending/descending). When the user presses a sortable column
header, the column's key and sort direction is passed into the onSortChange
callback,
allowing you to update the sortDescriptor
appropriately.
We recommend using the useAsyncList
hook from @react-stately/data to manage the data sorting. So make
sure to install it before using the sorting feature.
npm install @react-stately/data
import {useAsyncList} from "@react-stately/data";
Note that we passed the
isLoading
andloadingContent
props toTableBody
to render a loading state while the data is being fetched.
Loading more data
Table allows you to add a custom component at the end of the table, on the example below we are using a button to load more data.
Note: We passed the
isHeaderSticky
to theTable
component to make the header sticky.
Paginated Table
You can use the Pagination component to paginate the table.
Async Pagination
It is also possible to use the Pagination component to paginate the table asynchronously. To fetch the data, we are using the useSWR
hook from SWR.
Infinite Pagination
Table also supports infinite pagination. To do so, you can use the useAsyncList
hook from @react-stately/data and
@nextui-org/use-infinite-scroll hook.
npm install @react-stately/data @nextui-org/use-infinite-scroll
import { useInfiniteScroll } from "@nextui-org/use-infinite-scroll";import { useAsyncList } from "@react-stately/data";
Use Case Example
When creating a table, you usually need core functionalities like sorting, pagination, and filtering. In the example below, we combined all these functionalities to create a complete table.
Slots
- base: Defines a flexible column layout and relative positioning for the table component.
- wrapper: Applies to the outermost wrapper, providing padding, flexible layout, relative positioning, visual styles, and scrollable overflow handling.
- table: Sets the table to have a full minimum width and auto-adjusting height.
- thead: Specifies rounded corners for the first child row in the table header.
- tbody: No specific styles are applied to the body of the table.
- tr: Styles for table rows including group focus, outline properties, and a set of undefined focus-visible classes.
- th: Styles for table headers, including padding, text alignment, font properties, and special styles for sortable columns.
- td: Applies to table cells, with properties for padding, alignment, and relative positioning, plus special styles for first child elements, selection indication, and disabled cells.
- tfoot: No specific styles are applied to the footer of the table.
- sortIcon: Styles for sorting icons, with properties for margin, opacity, and transition effects based on sorting direction and hover state.
- emptyWrapper: Defines style for an empty table, with text alignment, color, and a specified height.
- loadingWrapper: Style applied when the table is loading, positioning it centrally in its container.
Custom Styles
You can customize the Table
component by passing custom Tailwind CSS classes to the component slots.
Data Attributes
TableBody
has the following attributes:
- data-empty: When the table is empty.
- data-loading:
When the table data is loading. Based on
TableBody
isLoading
andloadingContent
props.
TableRow
has the following attributes:
- data-selected:
When the row is selected. Based on
Table
selectedKeys
prop. - data-disabled:
When the row is disabled. Based on
Table
disabledKeys
prop. - data-hover: When the row is being hovered. Based on useHover
- data-focus-visible: When the row is being focused with the keyboard. Based on useFocusRing.
- data-first: When the row is the first row.
- data-middle: When the row is in the middle.
- data-odd: When the row is odd.
- data-last: When the row is the last row.
TableCell
has the following attributes:
- data-selected:
When the cell row is selected. Based on
Table
selectedKeys
prop. - data-focus-visible: When the cell is being focused with the keyboard. Based on useFocusRing.
Accessibility
- Exposed to assistive technology as a grid using ARIA.
- Keyboard navigation between columns, rows, cells, and in-cell focusable elements via the arrow keys.
- Single, multiple, or no row selection via mouse, touch, or keyboard interactions.
- Support for disabled rows, which cannot be selected.
- Column sorting support.
- Async loading, infinite scrolling, filtering, and sorting support.
- Support for both toggle and replace selection behaviors.
- Labeling support for accessibility.
- Ensures that selections are announced using an ARIA live region.
- Support for marking columns as row headers, which will be read when navigating the rows with a screen reader.
- Optional support for checkboxes in each row for selection, as well as in the header to select all rows.
- Automatic scrolling support during keyboard navigation.
- Support for row actions via double click, Enter key, or tapping.
- Typeahead to allow focusing rows by typing text.
- Long press to enter selection mode on touch when there is both selection and row actions.
API
Table Props
Attribute | Type | Description | Default |
---|---|---|---|
children* | ReactNode[] | The elements that make up the table. Includes the TableHeader , TableBody , TableColumn , and TableRow . | - |
color | default | primary | secondary | success | warning | danger | Color of the selected rows, and checkboxes. | default |
layout | auto | fixed | Defines the layout of the table. | auto |
radius | none | sm | md | lg | The border-radius of the table. | lg |
shadow | none | sm | md | lg | The shadow size of the table. | sm |
hideHeader | boolean | Whether to hide the table header. | false |
isStriped | boolean | Whether to apply striped rows in the table. | false |
isCompact | boolean | Whether to apply compact style to the table. | false |
isHeaderSticky | boolean | Whether to make the table header sticky. | false |
fullWidth | boolean | Whether to make the table full width. | true |
removeWrapper | boolean | Whether the table base container should not be rendered. | false |
BaseComponent | React.ComponentType<any> | A custom wrapper component for the table. | div |
topContent | ReactNode | Provides content to include a component in the top of the table. | - |
bottomContent | ReactNode | Provides content to include a component in the bottom of the table. | - |
topContentPlacement | inside | outside | Where to place the topContent component. | inside |
bottomContentPlacement | inside | outside | Where to place the bottomContent component. | inside |
showSelectionCheckboxes | boolean | Whether the row selection checkboxes should be displayed. | - |
sortDescriptor | SortDescriptor | The current sorted column and direction. | - |
selectedKeys | Selection | The currently selected keys in the collection (controlled). | - |
defaultSelectedKeys | Selection | The initial selected keys in the collection (uncontrolled). | - |
disabledKeys | Selection | A set of keys for rows that are disabled. | - |
disallowEmptySelection | boolean | Whether the collection allows empty selection. | - |
selectionMode | single | multiple | none | The type of selection that is allowed in the collection. | none |
selectionBehavior | toggle | replace | How multiple selection should behave in the collection. | toggle |
disabledBehavior | selection | all | Whether disabledKeys applies to all interactions, or only selection. | selection |
allowDuplicateSelectionEvents | boolean | Whether onSelectionChange should fire even if the new set of keys is the same as the last. | - |
disableAnimation | boolean | Whether to disable the table and checkbox animations. | false |
checkboxesProps | CheckboxProps | Props to be passed to the checkboxes. | - |
classNames | Record<"base" | "table" | "thead" | "tbody" | "tfoot" | "emptyWrapper" | "loadingWrapper" | "wrapper" | "tr" | "th" | "td" | "sortIcon", string> | Allows to set custom class names for the dropdown item slots. | - |
Table Events
Attribute | Type | Description |
---|---|---|
onRowAction | (key: React.Key) => void | Handler that is called when a user performs an action on the row. |
onCellAction | (key: react.Key) => void | Handler that is called when a user performs an action on the cell. |
onSelectionChange | (keys: Selection) => any | Handler that is called when the selection changes. |
onSortChange | (descriptor: SortDescriptor) => any | Handler that is called when the sorted column or direction changes. |
TableHeader Props
Attribute | Type | Description | Default |
---|---|---|---|
children* | ReactNode[] | A list of Column(s) or a function. If the latter, a list of columns must be provided using the columns prop | - |
columns | T[] | A list of table columns. | - |
TableColumn Props
Attribute | Type | Description | Default |
---|---|---|---|
children* | ReactNode | Static child columns or content to render as the column header | - |
align | start | center | end | The alignment of the column's contents relative to its allotted width | start |
hideHeader | boolean | Whether the column should hide its header text | false |
allowsSorting | boolean | Whether the column allows sorting | - |
isRowHeader | boolean | Whether a column is a row header and should be announced by assistive technology during row navigation | - |
textValue | string | A string representation of the column's contents, used for accessibility announcements | - |
width | string | number | The width of the column | - |
minWidth | string | number | The minimum width of the column | - |
maxWidth | string | number | The maximum width of the column | - |
TableBody Props
Attribute | Type | Description | Default |
---|---|---|---|
children* | RowElement | RowElement[] | ((item: T) => RowElement) | The contents of the table body. Supports static items or a function for dynamic rendering | - |
items | Iterable<T> | A list of row objects in the table body used when dynamically rendering rows | - |
isLoading | boolean | Whether the table body is loading. | - |
loadingState | LoadingState | Handler that is called when more items should be loaded, e.g. while scrolling near the bottom | - |
loadingContent | ReactNode | Content to display while loading more items | - |
emptyContent | ReactNode | Content to display when there are no items in the table body | - |
TableBody Events
Attribute | Type | Description |
---|---|---|
onLoadMore | () => any | A list of row objects in the table body used when dynamically rendering rows |
TableRow Props
Attribute | Type | Description | Default |
---|---|---|---|
children* | CellElement | CellElement[] | CellRenderer | Rendered contents of the row or row child items | - |
textValue | string | A string representation of the row's contents, used for features like typeahead | - |
TableCell Props
Attribute | Type | Description | Default |
---|---|---|---|
children* | ReactNode | The contents of the cell | - |
textValue | string | A string representation of the row's contents, used for features like typeahead | - |
Table types
Sort descriptor
type SortDescriptor = {column: React.Key;direction: "ascending" | "descending";};
Selection
type Selection = "all" | Set<React.Key>;
Loading state
type LoadingState = "loading" | "sorting" | "loadingMore" | "error" | "idle" | "filtering";