Skip to main content
Version: 4.xx.xx

6. Adding Sort and Filters

Sort and Filters​

The @refinedev/react-table package is based on the TanStack Table package, meaning that we can add sorting and filtering features to our table as suggested in the TanStack documentation.

Tanstack Table keeps the sorting and filters states in the useTable hook. When these states are changed, the useTable hook will automatically fetch the data and update the table with the new data.

info

Under the hood, sortingΒ and filters states of Tanstack Table are converted to the CrudSorting and CrudFilter types of refine. So, when you change the Tanstack Table's sorting or filters state, useTable hook will pass the converted params to the getList method of the dataProvider.

Since @refinedev/react-table provides a headless solution, there are many ways to handle filtering and sorting. In this tutorial, we will show a basic way of adding sorting and filtering to the table.

Adding Sorting​

We first need to add a clickable column header to the table, which, when clicked on, will sort the table by the column.

To do this, just open the src/pages/blog-posts/list.tsx file on your editor and replace the <thead> element with the following code:

src/pages/blog-posts/list.tsx
<thead>
{getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id}>
<div onClick={header.column.getToggleSortingHandler()}>
{!header.isPlaceholder &&
flexRender(
header.column.columnDef.header,
header.getContext(),
)}
{{
asc: " πŸ”Ό",
desc: " πŸ”½",
}[header.column.getIsSorted() as string] ?? null}
</div>
</th>
))}
</tr>
))}
</thead>

In the above code, we have added an onClick event to the column header. When the user clicks on the column header, the getToggleSortingHandler method of the column will be called, which will toggle the sorting state.

An arrow icon was also added to display the sorting state: no icon is shown if the column isn't sorted, πŸ”Ό is displayed for ascending order, and πŸ”½ is displayed for descending order.

tip

If you want to disable sorting for a specific column, you can set the enableSorting property of the column to false in the column definition:

{
title: "Category",
dataIndex: "category",
enableSorting: false,
},

Adding Filters​

We will just add a basic text input to the table header that will filter the table by the column value.

To do this, open the src/pages/blog-posts/list.tsx file on your editor and change the filter operator for columns to "contains" by changing the meta property of the column definition like below:

{
id: "title",
accessorKey: "title",
header: "Title",
meta: {
filterOperator: "contains",
},
},
{
id: "content",
accessorKey: "content",
header: "Content",
meta: {
filterOperator: "contains",
},
},
note

There are many values that you can pass to the filterOperator, for more information about them, refer to the Filtering section of the useTable documentation→

You then need to disable filtering for the "actions" column by setting the enableFiltering property of the column to false in the column definition like below:

{
id: "actions",
accessorKey: "id",
header: "Actions",
enableColumnFilter: false,
cell: function render({ getValue }) {
return (
<div
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
gap: "4px",
}}
>
<button
onClick={() => {
show("blog_posts", getValue() as string);
}}
>
Show
</button>
<button
onClick={() => {
edit("blog_posts", getValue() as string);
}}
>
Edit
</button>
</div>
);
},
},

Finally, you need to replace the <thead/> element with the following code:

<thead>
{getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id}>
<div onClick={header.column.getToggleSortingHandler()}>
{!header.isPlaceholder &&
flexRender(
header.column.columnDef.header,
header.getContext(),
)}
{{
asc: " πŸ”Ό",
desc: " πŸ”½",
}[header.column.getIsSorted() as string] ?? null}
</div>
<div>
{header.column.getCanFilter() && (
<input
value={header.column.getFilterValue() as string}
onChange={(e) => {
header.column.setFilterValue(
e.target.value,
);
}}
placeholder={`Search ${header.column.columnDef.header}`}
/>
)}
</div>
</th>
))}
</tr>
))}
</thead>

In the above code, we have added a basic text input to the column header. When the user types in the input, the setFilterValue method of the column will be called which will set the filter value of the column.

tip

We added the enableColumnFilter property to the column definition, which will call the getCanFilter method of the column to determine whether the column should have a filter input or not. If you want to disable the filtering for a spesific column, set the enableColumnFilter property of the column to false in the column definition:

{
title: "Category",
dataIndex: "category",
enableColumnFilter: false,
},

For more information about sorting and filters, refer to the useTable documentation→


Checklist