Table
Table is a container for displaying information from a data set. It allows users to quickly scan, sort, compare, and take action on large amounts of data.
#
Importimport { Table } from '@volue/wave-react';
Table is a compound component that consists of multiple parts which can be composed together to achieve the desired table interface:
- ​
Table
: The wrapper that contains all the parts of a table. - ​
Table.Head
: The container that defines the head of the table's columns (equivalent of<thead>
HTML element). - ​
Table.Header
: A convenience container wrapping content intoTable.Head
with singleTable.Row
inside. - ​
Table.ColumnHeader
: Renders the header cell of a column (equivalent of native<th>
element). Wraps text content intoTable.TableColumnHeaderContent
and optionally showsTable.SortIndicator
. - ​
Table.ColumnHeaderContent
: Wrapper for column's header text contents. - ​
Table.Body
: The container grouping a set ofTable.Row
s that are main content of the table (equivalent of native<tbody>
element). - ​
Table.Row
: Renders table row (equivalent of native<tr>
element). - ​
Table.Cell
: Cell to be placed in theTable.Row
that displays single piece of data in the column (equivalent of native<td>
element). Wraps text content intoTable.CellContent
automatically. - ​
Table.CellContent
: Wrapper for cell's text contents. - ​
Table.SelectionCell
: ComposesTable.Cell
andTable.SelectionCellCheckbox
, to render a cell with checkbox for implementing selection of rows. - ​
Table.SelectionCellCheckbox
: Customized Checkbox component to be placed in the table cell. - ​
Table.Foot
: The container grouping a set ofTable.Row
s which is placed at the bottom of the table (equivalent of native<tfoot>
element). - ​
Table.Footer
: A convenience container wrapping content intoTable.Foot
with singleTable.Row
inside. - ​
Table.EmptyState
: The wrapper for providing additional context when the table data is either unavailable or nonexistent.
#
Examples#
BasicIf you need to display basic key and value pairs, consider Data List instead.
#
Table appearanceThe root Table
component accepts following properties to infuence the appearance of every cell:
- ​
cellSize
— controls the size of each cell. - ​
alignY
— controls vertical alignment of content inside cells. - ​
overflowStrategy
— wraps or truncate content inside a cell. - ​
highlightOnHover
— controls whether rows withinTable.Body
should be highlighted on hover. - ​
rowSeparation
- controls the appearance of row separation.
Outer outline of the Table
can be disabled by setting outlined
property to false
:
#
Cell appearanceThe Table.Cell
component accepts following props to adjust appearance:
- ​
align
— controls the horizontal alignment of cell contents. - ​
maxWidth
— sets the maximum width of the cell. - ​
minWidth
— sets the minimum width of the cell. - ​
width
— sets the width of the cell.
Since the table layout is created with CSS Flexbox​, all cells have evenly distributed widths by default.
#
Rows selectionUse Table.SelectionCell
to implement selection of rows.
#
Table overflowWhen there isn’t enough space to fit all the rows or columns within table's container, it becomes scrollable.
You can apply sticky positioning to Table.Header
and Table.Footer
along the vertical axis via the stickyOffset
property:
- ​the header will be offset against the top edge.
- ​the footer will be offset against the bottom edge.
Table.ColumnHeader
and Table.Cell
can be "sticky" along the horizontal axis:
- ​positive values (e.g.
0
) will offset the cell against the left edge. - ​negative values (e.g.
-0
) will offset the cell against the right edge.
When stickyOffset
is provided, the showDivider
property will default to true
.
#
Synced scrollBy default, stickyOffset
is relative to nearest scrolling ancestor (the Table
itself). If the table
doesn't scroll vertically within the overflowing container and you want the Table.Header
or Table.Footer
to stick while scrolling on the document window, use syncScroll
property.
When syncScroll
is enabled, table's row groups become scrolling containers instead of the Table
and their scrolling position is synced up.
More details about this technique are available in the following article: https://uxdesign.cc/position-stuck-96c9f55d9526​
#
Custom cell contentYou may provide any custom content to Table.ColumnHeader
and Table.Cell
.
Note that when providing ReactText
(string
and number
) content to Table.Cell
, the cells will benefit from improved re-render performance thanks to React.memo
.
Each individual table cell can support multiple rows of text. This is useful when you want to provide related details in a table without adding additional columns, such as placing an employee's email address beneath their name.
#
Row actionsRow actions can be represented as icon buttons. When there is only one action available, you may provide a tooltip for better clarity.
When multiple actions are available on the row, use Menu component for displaying list of actions.
In some cases, you may want to attach an action to an entire row.
#
Highlighting rowsYou can highlight individual rows with isHighlighted
property. Highlights provide additional visual prominence to a row and is useful to quickly differentiate it from other rows.
Keep in mind that users with visual impairments may not notice when rows are highlighted, so prefer not to rely on highlights alone to convey information.
Never use highlighted rows to indicate that a user has selected the row. Refer to rows selection example instead.
#
Row tonesTable.Row
supports setting tone
property.
Tones are typicaly used to emphasize the status of a row and faciliate users in identyfing which parts of the table require attention.
Supported tones include:
- ​
danger
- for statuses that imply error, failure or problem. - ​
success
- for statuses that are positive, e.g. confirmations. - ​
warning
- for statuses that are in-progress, pending, or that could require user intervention.
Be sure to utilize tones purposefully to convey important statuses. Excessive use of tones can lead to noisy interface with too many elements pulling user attention.
Row tones should not be used alone as the only indicator of status. Be sure to include actual status labels in the table itself when possible.
Note that you can provide a custom tone by using tone="custom"
property and assigning specific color to --table-cell-bg-color
CSS variable.
#
Cell tonesSimilar to row tones, a single cell also supports setting tone
property. This can be useful to grab a user’s attention on a specific cell(s) in the table.
Be sure to utilize tones purposefully to convey important statuses. Overuse of tones can dilute attention on what matters most.
When using Table
with cell tones, you may want to visually separate elements using showCellSeparation
property to enhance visual structure of the table.
#
Loading stateRather than using a Spinner component, you can use the Skeleton placeholders in the cells to create a more pleasant loading experience.
#
Empty stateWhen there is no data to feed the table or no match can be found while filtering, render Table.EmptyState
instead of Table.Body
to provide additional context for the user.
For example, if a table of users isn’t populated yet, the empty state within the table shows the user what data to expect and optionally offers an action to populate the table.
#
Table inside a cardThe table can be contextually styled to better fit the container it is placed into, such as Card.
Use addHorizontalWhitespace
property to add additional horizontal padding on the outer table cells equal to the card padding (or equal to the whitespace between adjacent cells when placed outside a card).
#
Overflowing cell contentYou may use useHasOverflow
hook to dynamically apply Tooltip only when content overflows Table.CellContent
area.
The tooltip will show full content when hovered over the abbreviated cell text.
Try manipulating cell widths or wrap long content into multiple lines with overflowStrategy
set to wrap
to prevent text content overflowing the cell.
#
Drag and dropWith libraries such as react-dnd
you can easily implement drag-and-drop feature over table rows and change their order.
Don't forget to wrap your App into DndProvider
with appropriate backend
value.
Check react-dnd docs​ for more information.
import { DndProvider } from 'react-dnd';import { HTML5Backend } from 'react-dnd-html5-backend';function App() {return (<DndProvider backend={HTML5Backend}><Main /></DndProvider>);}
react-dnd
provides a way to separate dragRef
and dropRef
to use them on different DOM elements. It can be useful when there are multiple actionable elements in table rows.
dragRef
and dropRef
can be merged into one ref
which can be useful to make whole rows draggable.
#
Integration with TanStack TableTable component consists of lightweight, "primitive" buliding blocks designed for composability. Primitives are low-level components that assume as little as possible about their usage and they don't own any complex state.
This works well for simple or static tables, but there are instances where functionality such as sorting, search, filtering, virtualization​ or pagination are required. This kind of functionality is out of scope for the Table component, as the spectrum of possible use-cases is too broad for a single component to cover effectively. We aim to avoid monolithic components with a lot of assumptions about how you use them and increased API surface area, i.e. endless prop configuration.
Whilst the Table component is limited out of the box, these same limitations make it very easy to integrate with third-party libraries which offer advanced functionality. One such library that we recommend is TanStack Table​. It is a headless UI library​, which supplies you with functions, state and utilities to add more advanced functionality and interactions to your tables. It does not bring any user interface or styles itself, making it a perfect extension for Wave's Table.
Examples below show how to combine some common TanStack Table​ features with Wave's Table.
To use TanStack Table features, you should install @tanstack/react-table
package in your project.
npm install @tanstack/react-table --save# oryarn add @tanstack/react-table
For a more comprehensive, full-featured demo of a data table built using TanStack Table​ and Table component, be sure to check out our Storybook​.
#
Basicimport {flexRender,getCoreRowModel,useReactTable,createColumnHelper} from '@tanstack/react-table';
#
Sorting columnsUse TanStack Table Sorting API​ together with onClick
and sort
properties on Table.ColumnHeader
to render the UI for a sort indicator and allow the user to change the sort order of the data.
You should only use client-side sorting if your data set is small and exists in-memory, otherwise sorting should be implemented by sorting in the actual database.
Custom sorting icon can be provided with sortIndicator
attribute. Check different icon by sorting Name
column below.
Table data can be sorted by multiple columns by clicking on a column header while holding down the shift key. This is controlled with the enableMultiSort property​.
import {flexRender,getCoreRowModel,getSortedRowModel,useReactTable,createColumnHelper} from '@tanstack/react-table';
#
FilteringFiltering data can be implemented with TanStack Table Filters API​.
Table data can be filtered globally with use of globalFilter
prop or it can be column filtered with columnFilters
.
import {flexRender,getCoreRowModel,getFilteredRowModel,useReactTable,createColumnHelper} from '@tanstack/react-table';
#
Selecting rowsRows selection can be implemented with Row Selection API​. In the example below batch actions will be shown upon rows selection.
import {flexRender,getCoreRowModel,useReactTable,createColumnHelper} from '@tanstack/react-table';
#
PaginationWith help of Pagination component to display the pagination UI and TanStack Pagination API​, larger table data sets can be split into pages.
Often pagination is performed server-side and Table
already receives only data for specific page. In that case manualPagination property​ is helpful.
Be mindful to provide an aria-description
attribute on the Table
to let the assistive technologies announce current pagination state.
import {flexRender,getCoreRowModel,getPaginationRowModel,useReactTable,createColumnHelper} from '@tanstack/react-table';
#
Columns visibilityToggling columns visibility can be implemented with Visiblity API​.
import {flexRender,getCoreRowModel,useReactTable,createColumnHelper} from '@tanstack/react-table';
#
Rows virtualizationRendering large amounts of rows can be inefficient. With virtualization​ (or windowing) of data, only currently visible rows are rendered to DOM to deliver best performance and user experience.
When only a subset of rows are visible, it's a good practice to let all users know which rows are being displayed.
Use the aria-rowcount
attribute on the Table
to let assistive technologies know the total number of rows available. Table.Row
should include aria-rowindex
attribute to indicate where each row is in relation to the total available rows.
Virtualization achieves best performance with a fixed row height, so it's not recommended to combine it with overflowStrategy="wrap"
.
import {flexRender,getCoreRowModel,useReactTable,createColumnHelper} from '@tanstack/react-table';import { useVirtualizer } from '@tanstack/react-virtual';
#
API Reference#
TableProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
alignY | enum | "center" |
cellSize | enum | "medium" |
overflowStrategy | enum | "truncate" |
highlightOnHover | boolean | true |
syncScroll | boolean | false |
aria-label * | string | No default value |
rowSeparation | enum | "dividers" |
outlined | boolean | true |
addHorizontalWhitespace | boolean | false |
showCellSeparation | boolean | false |
#
Table.HeadProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
stickyOffset | number | No default value |
#
Table.HeaderProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
stickyOffset | number | No default value |
#
Table.ColumnHeaderProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
align | enum | "left" |
maxWidth | CSSProperties['maxWidth'] | No default value |
minWidth | CSSProperties['minWidth'] | No default value |
width | CSSProperties['width'] | No default value |
stickyOffset | number | No default value |
showDivider | boolean | No default value |
onClick | function | No default value |
sort | enum | No default value |
sortIndicator | React.ReactElement | No default value |
#
Table.ColumnHeaderContentProp | Type | Default |
---|---|---|
as | enum | div |
css | StitchesCss | No default value |
overflowStrategy | enum | No default value |
#
Table.SortIndicatorProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
#
Table.BodyProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
#
Table.RowProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
status | enum | No default value |
isHighlighted | boolean | false |
tone | enum | No default value |
#
Table.CellProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
align | enum | "left" |
maxWidth | CSSProperties['maxWidth'] | No default value |
minWidth | CSSProperties['minWidth'] | No default value |
width | CSSProperties['width'] | No default value |
stickyOffset | number | No default value |
showDivider | boolean | No default value |
role | enum | "gridcell" |
tone | enum | No default value |
#
Table.CellContentIn addition to the props below, you can pass Text props.
Prop | Type | Default |
---|---|---|
as | enum | div |
css | StitchesCss | No default value |
overflowStrategy | enum | No default value |
#
Table.SelectionCellIn addition to the props below, you can pass all Table.SelectionCellCheckbox props.
Prop | Type | Default |
---|---|---|
css | StitchesCss | No default value |
align | enum | "left" |
width | CSSProperties['width'] | No default value |
stickyOffset | number | No default value |
showDivider | boolean | No default value |
role | enum | gridcell |
aria-label * | string | No default value |
#
Table.SelectionCellCheckboxIn addition to the props below, you can pass all Checkbox props.
Prop | Type | Default |
---|---|---|
css | StitchesCss | No default value |
aria-label * | string | No default value |
#
Table.FootProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
stickyOffset | number | No default value |
#
Table.FooterProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |
stickyOffset | number | No default value |
#
Table.EmptyStateProp | Type | Default |
---|---|---|
css | StitchesCss | No default value |