2024-09-09 web, development, javascript
Building an Expandable Table with React Table
By O. Wolfson
Introduction
This is an overview on how to build an Expandable Table using Next.js, React Table, and shadcn/ui UI components. shadcn/ui is a modern, simple, and customizable collection of UI components compatible with React and Tailwind CSS. It provides components that can be used to build beautiful and responsive user interfaces.
We will create an expandable data table where each row represents a record that can be expanded to show more detailed information about the record. This kind of table is useful in various scenarios, for example, in a file system where files are organized in a hierarchical structure. shadcn/ui provides a Table
component, based on React (Tanstack) Table that makes it easy to create such tables.
We'll walk through the entire process of setting up the project, explaining the code, and providing code snippets to help you understand each step. By the end of this overview, you should have a clear understanding of how to React table and shadcn/ui together to create an expandable data table.
Link to example and source code.
You can preview the final product of this project here and the source code can be found on GitHub.
Here is an example of a React Table expandable table with pagination. and the source code.
Overview
- Create a Next.js project or other react based project. I am using Next.js 13 with Typescript and Tailwind CSS.
Install shadcn/ui and its peer dependencies used in its table component.
- Provide data to the table.
The above is the type definition for the data we'll be using in our table. Each item has an id
, name
, and parent
property. The parent
property is used to determine the hierarchy of the data. If an item has a parent
property, it's a child of the item with the corresponding id
. If an item has no parent
property, it's a root item.
Here is a link to some sample data:
-
useState Hooks: Here, we're using two hooks to store our data and the expanded state of our rows:
data
holds our table's data which initially comes from theexpandableData
object, andexpanded
holds the state of row expansion in our table. -
Columns Definition: The
columns
array defines the structure and behavior of our table. It uses theuseMemo
hook to ensure that the columns are only re-computed when necessary (in this case, they're static and never re-computed):Inside the
columns
array, we define one column with a nested column under it. The nested column uses thename
property from each data item for its values (accessorKey: "name"
).The nested column header contains a button to expand or collapse all rows in the table. The button's icon changes based on whether all rows are expanded or not.
The nested column cells also include buttons for expanding and collapsing individual rows. If a row is expandable (it has children), it displays a button with an icon that indicates whether the row is currently expanded or not. The row's depth in the data hierarchy determines its left padding.
-
Use of useReactTable hook: The
useReactTable
hook creates a table model from our data and column definitions and provides functions and properties for interacting with the table:The
useReactTable
hook is called with an object that includes our data and columns, along with several other properties:state
: the state of the table (currently, we're only tracking expanded state).onExpandedChange
: a function to update the expanded state when a row's expanded state changes.getSubRows
: a function to determine a row's children, if any.getCoreRowModel
,getFilteredRowModel
,getExpandedRowModel
: functions to customize row models at various stages of processing.debugTable
: enables debug mode for additional logging.
-
Rendering the Table: Lastly, we use the
table
model to generate our table's UI. We loop over thetable.getHeaderGroups()
to create headers for our table andtable.getRowModel().rows
to generate each row in the table body. If there are no rows to display, we show a "No results." message:
The above explanation should provide a comprehensive understanding of the DataTableDemo
component's behavior and structure. However, you might need to tailor the details according to the specific use-case and data set you're working with.