← All posts

Tutorial · September 26, 2026 · 5 min read

How to add a data table with sorting, search and pagination in React

To add a data table with sorting, search and pagination in React, install ReactFrame's free Data Table with npx shadcn@latest add @reactframe/data-table, describe your columns once and pass your rows as plain objects. Sorting, search, column filters, status tabs, pagination and row selection then work in the browser, which suits lists of up to a few thousand rows.

Admin panels, dashboards and internal tools all end up needing the same table: sortable columns, a search box, status tabs, pagination and a few row actions. Libraries like TanStack Table give you the logic but leave the UI to you. This tutorial uses ReactFrame's free Data Table, which ships both.

1. Install

npx shadcn@latest add @reactframe/data-table

2. Describe your columns and pass your rows

import { DataTable, type DataTableColumn } from "@/components/data-table";

const columns: DataTableColumn[] = [
  { key: "name", label: "Customer", type: "avatar", sortable: true },
  { key: "email", label: "Email", type: "text", sortable: true, filterable: true },
  { key: "plan", label: "Plan", type: "badge", sortable: true, filterable: true },
  { key: "mrr", label: "MRR", type: "currency", sortable: true, align: "right" },
  { key: "status", label: "Status", type: "badge", filterable: true },
  { key: "actions", label: "", type: "actions", align: "right" },
];

const rows = [
  { name: "Ada Lovelace", email: "ada@acme.com", plan: "Pro", mrr: 49, status: "Active" },
  { name: "Alan Turing", email: "alan@acme.com", plan: "Team", mrr: 199, status: "Active" },
  { name: "Grace Hopper", email: "grace@acme.com", plan: "Free", mrr: 0, status: "Inactive" },
];

export function CustomersTable() {
  return <DataTable title="Customers" columns={columns} data={rows} rowsPerPage={10} />;
}

Each row is a plain object; the column key says which field it reads. The column type decides how the cell looks:

TypeRenders
textPlain text.
numberA number, right for IDs and counts.
currencyA dollar amount with two decimals.
badgeA pill, coloured by badgeColors.
avatarInitials in a coloured circle next to the name.
actionsIcon buttons from actionButtons.

3. Search, filters and tabs

  • Search (showSearch) matches every column.
  • Column filters: columns with filterable: true get a filter menu in the header, listing that column's values.
  • Status tabs (showStatusTabs) build tabs from the values of one column, status by default; point statusTabsColumn at another field if needed.
  • Pagination (showPagination, rowsPerPage) and row selection (selectable) are on by default.

4. Colour the badges

<DataTable
  columns={columns}
  data={rows}
  badgeColors={[
    { value: "Active", background: "rgba(135,255,227,0.12)", text: "#87FFE3", dot: true },
    { value: "Inactive", background: "rgba(255,255,255,0.08)", text: "rgba(255,255,255,0.6)", dot: true },
    { value: "Pro", background: "rgba(124,92,255,0.14)", text: "#B6A6FF" },
  ]}
/>

When to reach for something else

This table sorts, searches and pages in the browser, which is ideal up to a few thousand rows. For tens of thousands of rows or data that lives on the server, page and filter in your API and pass one page of results at a time, or use a headless library such as TanStack Table for the logic.

Pair the table with charts and stat cards in the Dashboard kit.

Ahmet Loca

Ahmet Loca · Product designer

Hi, I'm Ahmet. I have over four years of experience creating intuitive, user-focused designs for digital products, and ReactFrame is where that work becomes components you can use in your own.

github.comx.comAbout ReactFrame