Table
A table gathers relational data. It displays values arranged to allow quick numerical analysis like comparison and sorting.
The HvTable
component offers a set of HTML-equivalent elements, styled to Design System's specification,
for building tables.
You can rely on these elements when your table doesn’t have many interactions or you need it to be very lightweight.
For better data handling and advanced features we recommend the use of the utility hooks collection. See the Table Hooks documentation for more details.
Please check our table examples and or the react-table
examples for
usage scenarios.
Table components
Each HTML table element (<table>
, <tr>
, <td>
, etc.) that a corresponding HvTable*
component.
These components provide the visual Design System alignment and support features such as sticky rows and header, sorting, resizing, etc.
Check out the props tab for the list of components and their properties.
Although it is possible to use the components directly, we recommended users
to use them along with the useHvTable
hook, which provides a
powerful API for managing tables.
Name | Age | Role |
---|---|---|
Alice | 30 | Designer |
Bob | 42 | Developer |
Charlie | 25 | QA |
Container components
Besides the primary table components, UI Kit provides a set of containers that help to organize the table layout:
HvTableSection
, which wraps the content in anHvSection
and further styles the children components.HvTableContainer
, which provides a scrollable area for the table content.HvLoadingContainer
, a loading container overlay to use while data is being fetched.
See also: HvBulkActions
, HvPagination
.
Section Title
Alice | 30 | Designer |
Bob | 42 | Developer |
Charlie | 25 | QA |
useHvTable
The UI Kit library provides a collection of custom hooks that ease the integration with the HvTable components and allows more advanced use cases and better data handling.
Our custom hooks are built on top of react-table@7
, an “headless” UI utility library to build data tables while retaining control over markup and styles.
It consists of a collection of lightweight, composable, and extensible custom React hooks.
The useHvTable
hook that wraps the react-table
’s useTable
hook and provides the additional functionality:
- Ensures the use of the needed core and layout plugins when using any of the UI Kit custom hooks (e.g. adding
useHvPagination
implies the installation of React Table’susePagination
hook). - Automatically installs the
useHvTableStyles
hook. - Generates default column metadata from the data fields, if the
columns
option is missing. - Defaults to an empty array if no
data
is provided.
Each primary feature (eg. sorting, pagination, etc.) is implemented as opt-in plugin hooks that can be used independently or in combination with other hooks.
The usage of of the useHvTable
hook along with the HvTable*
components is as follows:
Setup
export default function Demo() {
// 👇 Define the `data` and `columns` configuration (MUST be memoized).
const [data] = useState(() => makeData(1000));
const columns = useMemo<HvTableColumnConfig<AssetEvent>[]>(
() => [
{ Header: "Name", accessor: "name" },
{ Header: "Age", accessor: "age" },
{ Header: "Role", accessor: "role" },
],
[],
);
const table = useHvTable(
{ columns, data },
// 👇 Provide the plugin hooks that you need
useHvTableSticky,
useHvSortBy,
useHvPagination,
useHvRowSelection,
useHvBulkActions,
);
return (
// Spread the table props 👇 in the respective components
<HvTable {...table.getTableProps()}>
<HvTableHead {...table.getTableHeadProps?.()}>
{table.headerGroups.map((headerGroup) => (
<HvTableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((col) => (
<HvTableHeader {...col.getHeaderProps()}>
{col.render("Header")}
</HvTableHeader>
))}
</HvTableRow>
))}
</HvTableHead>
<HvTableBody {...table.getTableBodyProps?.()}>
{table.page.map((row) => {
// Render the Header and Cells using the `render` function:
table.prepareRow(row);
return (
<HvTableRow {...row.getRowProps()}>
{row.cells.map((cell) => (
<HvTableCell {...cell.getCellProps()}>
{cell.render("Cell")}
</HvTableCell>
))}
</HvTableRow>
);
})}
</HvTableBody>
</HvTable>
);
}
Usage
By leveraging HvTable*
components and the useHvTable
hook, you should be able to address any specific table scenario.
We recommend that you separate the table definition (HvTable*
and useHvTable
) from the implementation/usage (columns
and data
), by creating a reusable (eg. <Table>
) table component.
You should strive to have simple API that allows passing the data
and columns
, and not worrying about the layout or hook logic:
// simple usage
<Table data={data} columns={columns} />
// or with extra configuration
<Table
data={data}
columns={columns}
actions={[
{ id: "delete", label: "Delete" },
{ id: "clone", label: "Clone" },
]}
initialState={{
pageSize: 20,
}}
/>
useHvTable
hooks
The following react-table
plugin hooks are available to use with useHvTable
:
useHvPagination
: Eases the wiring of theHvPagination
component when using pagination.useHvRowSelection
: Creates and manages the UI for selecting rows.useHvBulkActions
: Eases the wiring of theHvBulkActions
component.useHvSortBy
: Manages the table’s header sorting functionality.useHvRowExpand
: Manages the row expanding functionality.useHvTableSticky
: Allows defining sticky headers and columns.useHvHeaderGroups
: Allows defining grouped headers.useHvResizeColumns
: Manages column resizing.
The additional hooks below are simply re-exports of the original react-table
hooks, or hooks that the UI Kit doesn’t re-exports
but are listed here for visibility. Please refer to the react-table
docs (linked) below for documentation and examples:
useHvRowState
: Implements basic state management for prepared rows and their cells.useHvGlobalFilter
: Manages global filtering.useHvFilters
: Manages column filtering.useColumnOrder
: Manages column ordering.useGroupBy
: Manages row grouping.useBlockLayout
,useAbsoluteLayout
,useFlexLayout
useHvPagination
Data can be paginated. Optionally, empty lines can be added to the last page to avoid changes in height.
Check React Table’s usePagination
documentation for configuration details.
The useHvPagination
hook makes the getHvPaginationProps
function available on the table instance returned that can be used to setup a
HvPagination
component:
const table = useHvTable({ columns, data }, useHvPagination);
return <HvPagination {...table?.getHvPaginationProps()} />;
useHvSortBy
Tables can have the capability of sorting the data by column. Clicking a sortable column header toggles between ascending or descending. Multiple sorting criteria
is enabled through holding shift while clicking.
Check React Table’s useSortBy
documentation for configuration details.
The useHvSortBy
hook ensures that the proper properties are injected in the HvTableHeader
(including the on click sorting trigger) and HvTableCell
(for styling).
useHvRowSelection
Rows can be selected individually.
Check React Table’s useRowSelect
documentation for configuration details.
The useHvRowSelection
hook injects a new column with a HvCheckBox
to select each row. It also manages the HvTableRow's
isSelected
property via the
getRowProps
.
This hook is originally based on the code useRowSelect
hook from react-table and implements its API, but extends it with support for locking the selection
state of individual rows.
useHvBulkActions
Rows can also be selected in bulk and actions can be performed on the current selection.
The useHvBulkActions
hook makes the getHvBulkActionsProps
function available on the table instance returned that can be used to setup a HvBulkActions
component.
const table = useHvTable({ columns, data }, useHvBulkActions);
return <HvBulkActions {...table?.getHvBulkActionsProps()} />;
useHvTableSticky
The table headers can be fixed at the top, allowing it to keep always visible when table has vertical scrolling enabled. It is also possible to stick columns, either on the left or on the right, making them always visible when scrolling horizontally.
When using sticky columns, all column widths will be fixed and a non-table-element layout is applied.
The following options are supported via the main options object passed to useTable(options)
:
stickyHeader: boolean
: Enables the sticky header.
The following options are supported on any Column
object passed to the columns
options in useTable()
:
sticky: "left" | "right"
: Sticks this column to the defined side. Columns will be re-orderer if needed.width: number
: Specifies the width for the column. Defaults to 150.minWidth: number
: Specifies the minimum width for the column. Defaults to 0.
Note: Ensure the getTableProps
, getTableHeadProps
, getHeaderGroupProps
, getHeaderProps
, getTableBodyProps
,
getRowProps
, and getCellProps
prop getters are injected into the corresponding components.
const columns = [
{ Header: "Name", accessor: "name", sticky: "left" }, // 👈 sticky column
{ Header: "Age", accessor: "age" },
{ Header: "Role", accessor: "role", sticky: "right", minWidth: 200 },
];
const table = useHvTable(
{ columns, data, stickyHeader: true },
useHvTableSticky, // 👆 sticky header and hook
);
useHvResizeColumns
Columns can be resized using the useHvResizeColumns
hook. Although this is not an accessible functionality, it allows columns to be resizable via dragging column right border.
Check React Table’s useResizeColumns
documentation for configuration details.
useHvRowExpand
Tables rows can have the capability of being expanded to show more details.
Check React Table’s useExpanded
documentation for configuration details.
The useHvRowExpand
hook injects a HvButton
into the first data column that toggles each row expansion. If the column has a custom renderer, an
extra column is created instead.
useHvHeaderGroups
The table columns can be grouped, allowing it to have header groups.
Check React Table’s useTable
documentation for configuration details.
This is implemented using the useHvHeaderGroups
custom React Table hook provided by the UI Kit library.
Note: When using grouped columns, all header group columns text will be centered.
const columns = [
{
id: "name"
Header: "Name",
// 👇 nested columns under "name"
columns: [
{ Header: "First", accessor: "firstName" },
{ Header: "Last", accessor: "lastName" },
],
},
];