Pagination

Add pagination to render a built-in pagination bar below the table. All state is managed internally. No extra props needed for basic usage.

Built-in pagination

30 rows. Use the buttons above to change the initial rows-per-page, or use the built-in selector inside the table.

Rows per page:30 total rows
Name
Department
Salary
Status
Aria Chen
Engineering
$80,000
Active
Marcus Webb
Product
$83,700
Remote
Priya Kapoor
Design
$87,400
On Leave
Jordan Ellis
Analytics
$91,100
Contractor
Sam Rivera
Sales
$94,800
Active

Server-side pagination

When your dataset is too large to load at once, delegate pagination to the server. Set paginationServer and provide paginationTotalRows so the pagination bar knows how many pages exist. Respond to onChangePage and onChangeRowsPerPage to fetch each page.

Server-side pagination

100-row simulated dataset with 300 ms fake network latency. Change pages or the rows-per-page selector to trigger a new fetch.

Name
Department
Salary
Status

Callback contract

When using server-side mode, the three callbacks are mutually exclusive. Only one fires per user interaction, never two at once:

User action Callback that fires What you should do
Click a sortable column header onSort(column, direction, rows) Fetch page 1 with the new sort. Update your local sort state and reset your local page to 1.
Click a page number / prev / next onChangePage(page, totalRows) Fetch the requested page with current sort params.
Change the rows-per-page selector onChangeRowsPerPage(newPerPage, currentPage) Fetch the recalculated page at the new page size with current sort params.

Sorting always resets to page 1. When the user sorts while on page 3, the pagination bar jumps back to page 1 automatically and onChangePage is not called. onSort is the sole callback, and it is your responsibility to fetch from page 1 and keep your own page state in sync:

function handleSort(col: TableColumn<Employee>, dir: SortOrder) {
  const field = col.sortField ?? String(col.id);
  setSortField(field);
  setSortDir(dir);
  setPage(1);   // keep local state in sync with the UI reset
  fetchData({ page: 1, perPage, sortField: field, sortDir: dir });
}

Combined: server-side sorting and pagination

Wire all three handlers together. Because sorting resets to page 1 and suppresses onChangePage, you only need one fetch per user action.

Server-side sort + pagination

150-row simulated dataset. Sort any column, then page through the results — each action triggers exactly one fetch (300 ms latency).

sort: "name" asc · page: 1 · perPage: 10 · total: 0
Name
Department
Salary
Status

Full example: search, sort, and pagination

A realistic pattern with an external search input. Searching is an external state change. It doesn't go through any of DataTable's callbacks, so toggle paginationResetDefaultPage yourself to reset the bar to page 1.

Search + sort + pagination

200-row simulated dataset with 350 ms fake network latency. Search, sort, and page. Each action triggers exactly one fetch.

Name
Department
Salary
Status

With React Query

Let TanStack Query own the fetch. Update state in the callbacks and the query key change triggers a refetch automatically. placeholderData: keepPreviousData prevents an empty flash between page transitions.

import { useState } from 'react';
import { useQuery, keepPreviousData } from '@tanstack/react-query';
import DataTable, { type TableColumn, SortOrder } from 'react-data-table-component';

export default function App() {
  const [page, setPage]           = useState(1);
  const [perPage, setPerPage]     = useState(10);
  const [sortField, setSortField] = useState('name');
  const [sortDir, setSortDir]     = useState<SortOrder>(SortOrder.ASC);

  const { data, isLoading } = useQuery({
    queryKey: ['employees', page, perPage, sortField, sortDir],
    queryFn: () =>
      fetch(`/api/employees?page=${page}&limit=${perPage}&sort=${sortField}&dir=${sortDir}`)
        .then(r => r.json()),
    placeholderData: keepPreviousData,
  });

  return (
    <DataTable
      columns={columns}
      data={data?.rows ?? []}
      progressPending={isLoading}
      pagination
      paginationServer
      paginationTotalRows={data?.total ?? 0}
      onChangePage={setPage}
      onChangeRowsPerPage={(pp) => { setPerPage(pp); setPage(1); }}
      sortServer
      onSort={(col, dir) => {
        setSortField(col.sortField ?? String(col.id));
        setSortDir(dir);
        setPage(1);
      }}
    />
  );
}

With SWR

import { useState } from 'react';
import useSWR from 'swr';
import DataTable, { type TableColumn, SortOrder } from 'react-data-table-component';

const fetcher = (url: string) => fetch(url).then(r => r.json());

export default function App() {
  const [page, setPage]       = useState(1);
  const [perPage, setPerPage] = useState(10);
  const [sort, setSort]       = useState({ field: 'name', dir: SortOrder.ASC });

  const url = `/api/employees?page=${page}&limit=${perPage}&sort=${sort.field}&dir=${sort.dir}`;
  const { data, isLoading } = useSWR(url, fetcher);

  return (
    <DataTable
      columns={columns}
      data={data?.rows ?? []}
      progressPending={isLoading}
      pagination
      paginationServer
      paginationTotalRows={data?.total ?? 0}
      onChangePage={setPage}
      onChangeRowsPerPage={(pp) => { setPerPage(pp); setPage(1); }}
      sortServer
      onSort={(col, dir) => {
        setSort({ field: col.sortField ?? String(col.id), dir });
        setPage(1);
      }}
    />
  );
}

Resetting to page 1

For external state changes (search, filter) that aren't triggered by a table callback, toggle paginationResetDefaultPage to reset the bar to page 1. Any change to this boolean (regardless of direction) triggers the reset.

const [resetPage, setResetPage] = useState(false);

function handleSearch(q: string) {
  setSearch(q);
  setPage(1);
  setResetPage(prev => !prev);
  fetchData({ page: 1, perPage, sortField, sortDir, q });
}

Persisting selection across pages

By default, navigating between pages clears selected rows. Use paginationServerOptions to retain selections across page changes and sorts:

<DataTable
  pagination
  paginationServer
  paginationServerOptions={{
    persistSelectedOnPageChange: true,
    persistSelectedOnSort: true,
  }}
/>

Custom pagination component

Replace the built-in pagination bar entirely by passing a component to paginationComponent. It receives rowsPerPage, rowCount, currentPage, onChangePage, and onChangeRowsPerPage as props.

import { type PaginationComponentProps } from 'react-data-table-component';

function MyPagination({ rowsPerPage, rowCount, currentPage, onChangePage }: PaginationComponentProps) {
  const pages = Math.ceil(rowCount / rowsPerPage);
  return (
    <div>
      <button disabled={currentPage === 1} onClick={() => onChangePage(currentPage - 1, rowCount)}>
        ‹ Prev
      </button>
      <span>Page {currentPage} of {pages}</span>
      <button disabled={currentPage === pages} onClick={() => onChangePage(currentPage + 1, rowCount)}>
        Next ›
      </button>
    </div>
  );
}

<DataTable
  columns={columns}
  data={data}
  pagination
  paginationComponent={MyPagination}
/>

Prop reference

Prop Type Default Description
pagination boolean false Enable the built-in pagination bar.
paginationPerPage number 10 Initial number of rows per page.
paginationDefaultPage number 1 Initial page number.
paginationRowsPerPageOptions number[] [10, 25, 50, 100] Options shown in the rows-per-page dropdown.
paginationServer boolean false Delegate pagination to the server. Use with paginationTotalRows and the change callbacks.
paginationTotalRows number 0 Total row count across all pages (server-side only). Used to calculate total pages.
paginationResetDefaultPage boolean false Toggle this value to reset the pagination bar to page 1 (e.g. after a search).
paginationServerOptions { persistSelectedOnPageChange?, persistSelectedOnSort? } - Server-side selection persistence options.
paginationComponent ComponentType<PaginationComponentProps> - Replaces the built-in pagination bar with a custom component.
paginationComponentOptions PaginationOptions - Options forwarded to the default pagination component (label customisation, etc.).
paginationIconFirstPage ReactNode - Icon for the "first page" button.
paginationIconLastPage ReactNode - Icon for the "last page" button.
paginationIconNext ReactNode - Icon for the "next page" button.
paginationIconPrevious ReactNode - Icon for the "previous page" button.
onChangePage (page: number, totalRows: number) => void - Called when the user navigates to a different page.
onChangeRowsPerPage (currentRowsPerPage: number, currentPage: number) => void - Called when the user changes the rows-per-page selection.