How to Create DaisyUI Table with Sorting and Pagination (Typescript)
Jasser Mark Arioste
In our previous tutorial, we learned how to create a basic table using DaisyUI and react-table. It had a very basic functionality which is just to display a table. Today, we're going to add client-side sorting and pagination to that table using react-table@v8.x.x
.
To follow along with this tutorial, you don't necessarily need to use the DaisyUI library, you can also use bootstrap or whatever UI library you want. The main focus in this tutorial is how to use react-table to implement client-side sorting and pagination. However if you wish to follow along from the start, take a look at our previous tutorial. Note that we'll also be using typescript in this tutorial.
With that out of the way, let's start!
Adding Client-Side Sorting functionality #
To add sorting functionality to our table we only really need to do two things:
- Modify useTable hook to add the options necessary to calculate the sorted rows and calculate the sort state of the table.
- Modify the header to add sort functionality and display the current sorted column
Modifying the useTable
hook to add sort functionality.
Check steps in the code below.
//components/Table.tsx ... const Table = () => { //1. add a sorting state using useState hook, this will allow us to keep track of the state const [sorting, setSorting] = React.useState<SortingState>([]); const table = useReactTable({ columns: userColumnDefs, data: data as Person[], getCoreRowModel: getCoreRowModel(), //2. add getSortedRowModel into the pipeline. this will calculate the sorted rows when the sort state changes getSortedRowModel: getSortedRowModel(), //3. add state to our table we use the sorting state from step 1 state: { sorting, }, //4. add a handler for onSortingChange using the setSorting from step 1 onSortingChange: setSorting, }); ... }
1234567891011121314151617181920
Modifying the th elements to add sorting indicators and handlers
Checkout the steps in the code below:
//components/Table.tsx const Table = ()=> { ... return ( ... <thead> <tr> {headers.map((header) => { //5. check if the column is sorted const direction = header.column.getIsSorted(); //6. create a map to get the sorting indicator const arrow: any = { asc: "🔼", desc: "🔽", }; //6. get the sorting indicator if header is sorted const sort_indicator = direction && arrow[direction]; return ( <th key={header.id}> {header.isPlaceholder ? null : ( //7. add an onClick handler using header.column.getToggleSortingHandler <div onClick={header.column.getToggleSortingHandler()} // 8. add a class to render the sorting indicator properly className="cursor-pointer flex gap-4" > {flexRender( header.column.columnDef.header, header.getContext() )} {/* 9. render the sorting indicator */} {direction && <span>{sort_indicator}</span>} </div> )} </th> ); })} </tr> </thead> ... ) }
123456789101112131415161718192021222324252627282930313233343536373839404142434445
With everything done you should have a table with sorting functionality:
Adding Pagination #
To add a pagination component to our table we need to do 3 things:
- Add pagination to the row calculation pipeline by using getPaginationRowModel provided by react-table
- Create a Pagination component and make use of react-tables pagination functions to modify the pagination state.
- Use the Pagination component in our table component.
Using getPaginationRowModel
to add a pagination pipeline
//components/Table.tsx import { flexRender, getCoreRowModel, getSortedRowModel, // 1. add necessary import getPaginationRowModel, SortingState, useReactTable, } from "@tanstack/react-table"; ... const Table = () => { ... const table = useReactTable({ columns: userColumnDefs, data: data as Person[], getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), //2. add getPaginationRowModel getPaginationRowModel: getPaginationRowModel(), state: { sorting, }, onSortingChange: setSorting, }); ... }
123456789101112131415161718192021222324252627
By default this will calculate the rows and return the first 10 rows of our table. We can change how many rows we want to display later when creating the Pagination
component.
Creating the Pagination component:
Let's create the pagination component. Create a file components/Pagination.tsx
and copy-past the code below.
//components/Pagination.tsx import { Table } from "@tanstack/react-table"; import React from "react"; type Props = { // table returned from useTable hook. table: Table<any>; }; const Pagination = ({ table }: Props) => { // pagination state const state = table.getState().pagination; //last page helper function const goLastPage = () => table.setPageIndex(table.getPageCount() - 1); return ( <div className="my-2"> <div className="flex items-center gap-2"> <div className="btn-group btn-sm"> {/* button to go to first page */} <button className="btn btn-sm" onClick={() => table.setPageIndex(0)} disabled={!table.getCanPreviousPage()} > {"<<"} </button> {/* button to go previous page */} <button className="btn btn-sm" onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()} > {"<"} </button> {/* button to go next page */} <button className="btn btn-sm" onClick={() => table.nextPage()} disabled={!table.getCanNextPage()} > {">"} </button> {/* button to go last page */} <button className="btn btn-sm" onClick={goLastPage} disabled={!table.getCanNextPage()} > {">>"} </button> </div> {/* page info */} <span className="flex items-center gap-1"> <div>Page</div> <strong> {state.pageIndex + 1} of {table.getPageCount()} </strong> </span> {/* input to skip to a specific page */} <span className="flex items-center gap-1"> | Go to page: <input defaultValue={state.pageIndex + 1} type="number" onChange={(e) => { const page = e.target.value ? Number(e.target.value) - 1 : 0; table.setPageIndex(page); }} className="input input-bordered w-20 input-sm mx-2" /> </span> {/* select to input page size */} <select value={state.pageSize} onChange={(e) => { table.setPageSize(Number(e.target.value)); }} className="select select-sm select-bordered" > {[10, 20, 30, 40, 50].map((pageSize) => ( <option key={pageSize} value={pageSize}> Show {pageSize} </option> ))} </select> </div> </div> ); }; export default Pagination;
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
In our pagination component, we are using functions provided by the useTableHook
to modify the pagination state. These functions include table.setPageIndex
, table.getCanPreviousPage
, table.setPageSize
which are pretty self-explanatory based on their function name.
Using the Pagination component #
In order to use the Pagination component, we have to call it from inside our Table component.
//components/Table.tsx ... import Pagination from "./Pagination"; ... const Table = () => { const [sorting, setSorting] = React.useState<SortingState>([]); const table = useReactTable({ columns: userColumnDefs, data: data as Person[], getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), //2. add getPaginationRowModel getPaginationRowModel: getPaginationRowModel(), state: { sorting, }, onSortingChange: setSorting, }); const headers = table.getFlatHeaders(); const rows = table.getRowModel().rows; return ( <div> ... <Pagination table={table} /> </div> ); };
12345678910111213141516171819202122232425262728
And we're done! Adding sorting and pagination functionality to our table was not as hard as we expected. Here are the results of our pagination component.
Below are some questions you might ask regarding react-table
How to add server-side pagination and sorting? #
We'll cover this in our next tutorial.
Is it wise to create a Table with multiple functionalities that can be used with all sorts of data? #
In my opinion, nope. that's a bad idea. We should create a different table depending on the functionality needed and use react-table
to get the necessary functionality we need. react-table
provides a good way of plug-and-play functionality that keeps our codebase clean and free of clutter.
Resources #
react-table docs: https://tanstack.com/table/v8
If you like articles like these, please subscribe to our newsletter. Also if you have a tutorial you want me to demo, please contact me through our contact page.
Credits: Image by Simon from Pixabay