CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-table

Hooks for building lightweight, fast and extendable datagrids for React

Pending
Overview
Eval results
Files

pagination.mddocs/

Pagination

React Table provides built-in pagination functionality that handles large datasets efficiently. The pagination system supports both client-side and server-side pagination with intuitive navigation controls and configurable page sizes.

Capabilities

usePagination Hook

Enables pagination functionality with automatic page calculations and navigation methods.

/**
 * Adds pagination capabilities to the table
 * @param hooks - Hook registration object
 */
function usePagination(hooks: Hooks): void;

interface PaginationInstance {
  /** Array of available page indices */
  pageOptions: number[];
  /** Total number of pages */
  pageCount: number;
  /** Current page of rows (subset of all rows) */
  page: Row[];
  /** Whether previous page is available */
  canPreviousPage: boolean;
  /** Whether next page is available */
  canNextPage: boolean;
  /** Navigate to specific page by index */
  gotoPage: (pageIndex: number) => void;
  /** Go to previous page */
  previousPage: () => void;
  /** Go to next page */
  nextPage: () => void;
  /** Change the number of rows per page */
  setPageSize: (pageSize: number) => void;
}

Configuration Options:

interface PaginationOptions {
  /** Disable automatic pagination */
  manualPagination?: boolean;
  /** Total number of pages (for manual pagination) */
  pageCount?: number;
  /** Whether to include expanded rows in pagination */
  paginateExpandedRows?: boolean;
  /** Auto-reset to first page when data changes */
  autoResetPage?: boolean;
  /** Initial pagination state */
  initialState?: {
    pageIndex?: number;
    pageSize?: number;
  };
}

Usage Example:

import React from 'react';
import { useTable, usePagination } from 'react-table';

function PaginatedTable({ columns, data }) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    page, // Instead of 'rows', use 'page'
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data,
      initialState: { pageIndex: 0, pageSize: 10 },
    },
    usePagination
  );

  return (
    <div>
      <table {...getTableProps()}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                <th {...column.getHeaderProps()}>
                  {column.render('Header')}
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {page.map(row => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => (
                  <td {...cell.getCellProps()}>
                    {cell.render('Cell')}
                  </td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>

      {/* Pagination Controls */}
      <div className="pagination">
        <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
          {'<<'}
        </button>
        <button onClick={() => previousPage()} disabled={!canPreviousPage}>
          {'<'}
        </button>
        <button onClick={() => nextPage()} disabled={!canNextPage}>
          {'>'}
        </button>
        <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
          {'>>'}
        </button>
        <span>
          Page{' '}
          <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
        </span>
        <span>
          | Go to page:{' '}
          <input
            type="number"
            defaultValue={pageIndex + 1}
            onChange={e => {
              const page = e.target.value ? Number(e.target.value) - 1 : 0;
              gotoPage(page);
            }}
            style={{ width: '100px' }}
          />
        </span>{' '}
        <select
          value={pageSize}
          onChange={e => {
            setPageSize(Number(e.target.value));
          }}
        >
          {[10, 20, 30, 40, 50].map(pageSize => (
            <option key={pageSize} value={pageSize}>
              Show {pageSize}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
}

Server-Side Pagination

Handle pagination on the server side for large datasets that cannot be loaded entirely into memory.

function ServerPaginatedTable({ columns }) {
  const [data, setData] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [pageCount, setPageCount] = React.useState(0);

  const fetchData = React.useCallback(({ pageIndex, pageSize }) => {
    setLoading(true);
    // Fetch data from server
    fetchServerData(pageIndex, pageSize).then(response => {
      setData(response.data);
      setPageCount(Math.ceil(response.total / pageSize));
      setLoading(false);
    });
  }, []);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    page,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageOptions,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data,
      initialState: { pageIndex: 0, pageSize: 10 },
      manualPagination: true, // Tell the table we'll handle pagination
      pageCount, // Pass our known page count
    },
    usePagination
  );

  // Listen for changes in pagination and use the state to fetch new data
  React.useEffect(() => {
    fetchData({ pageIndex, pageSize });
  }, [fetchData, pageIndex, pageSize]);

  return (
    <div>
      {loading && <div>Loading...</div>}
      
      <table {...getTableProps()}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                <th {...column.getHeaderProps()}>
                  {column.render('Header')}
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {page.map(row => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => (
                  <td {...cell.getCellProps()}>
                    {cell.render('Cell')}
                  </td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>

      {/* Pagination controls remain the same */}
      <div className="pagination">
        {/* ... pagination controls ... */}
      </div>
    </div>
  );
}

Pagination with Filtering and Sorting

Combine pagination with other table features for a complete data management solution.

import React from 'react';
import { 
  useTable, 
  useFilters, 
  useGlobalFilter, 
  useSortBy, 
  usePagination 
} from 'react-table';

function FullFeaturedTable({ columns, data }) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    page,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    setGlobalFilter,
    preGlobalFilteredRows,
    state: { pageIndex, pageSize, globalFilter },
  } = useTable(
    {
      columns,
      data,
      initialState: { pageIndex: 0, pageSize: 10 },
    },
    useFilters,
    useGlobalFilter,
    useSortBy,
    usePagination // usePagination should be last
  );

  return (
    <div>
      {/* Global Search */}
      <div>
        <input
          value={globalFilter || ''}
          onChange={e => setGlobalFilter(e.target.value)}
          placeholder="Search all columns..."
        />
      </div>

      <table {...getTableProps()}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                <th {...column.getHeaderProps(column.getSortByToggleProps())}>
                  <div>
                    {column.render('Header')}
                    <span>
                      {column.isSorted
                        ? column.isSortedDesc
                          ? ' 🔽'
                          : ' 🔼'
                        : ''}
                    </span>
                  </div>
                  {/* Column Filter */}
                  <div>
                    {column.canFilter ? column.render('Filter') : null}
                  </div>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {page.map(row => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => (
                  <td {...cell.getCellProps()}>
                    {cell.render('Cell')}
                  </td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>

      {/* Pagination */}
      <div className="pagination">
        <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
          {'<<'}
        </button>
        <button onClick={() => previousPage()} disabled={!canPreviousPage}>
          {'<'}
        </button>
        <button onClick={() => nextPage()} disabled={!canNextPage}>
          {'>'}
        </button>
        <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
          {'>>'}
        </button>
        <span>
          Page{' '}
          <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
          | Showing {page.length} of {preGlobalFilteredRows.length} results
        </span>
        <select
          value={pageSize}
          onChange={e => setPageSize(Number(e.target.value))}
        >
          {[10, 20, 30, 40, 50].map(pageSize => (
            <option key={pageSize} value={pageSize}>
              Show {pageSize}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
}

Pagination State Management

Control pagination state externally for integration with routing or external state management.

function ControlledPaginationTable({ columns, data }) {
  const [paginationState, setPaginationState] = React.useState({
    pageIndex: 0,
    pageSize: 25,
  });

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    page,
    prepareRow,
    pageCount,
    state,
  } = useTable(
    {
      columns,
      data,
      initialState: paginationState,
      // Control state updates
      stateReducer: (newState, action) => {
        // Update external state
        if (action.type.includes('page') || action.type.includes('Page')) {
          setPaginationState({
            pageIndex: newState.pageIndex,
            pageSize: newState.pageSize,
          });
        }
        return newState;
      },
    },
    usePagination
  );

  // Sync URL with pagination state
  React.useEffect(() => {
    const url = new URL(window.location);
    url.searchParams.set('page', (state.pageIndex + 1).toString());
    url.searchParams.set('size', state.pageSize.toString());
    window.history.replaceState({}, '', url);
  }, [state.pageIndex, state.pageSize]);

  return (
    <div>
      <table {...getTableProps()}>
        {/* Table implementation */}
      </table>
      
      <div>
        Current page: {state.pageIndex + 1} of {pageCount}
        <br />
        Page size: {state.pageSize}
      </div>
    </div>
  );
}

Advanced Pagination Features

Additional pagination utilities and customization options.

interface PaginationState {
  /** Current page index (0-based) */
  pageIndex: number;
  /** Number of rows per page */
  pageSize: number;
}

interface PaginationMethods {
  /** Navigate to first page */
  gotoPage: (pageIndex: number) => void;
  /** Go to next page if possible */
  nextPage: () => void;
  /** Go to previous page if possible */
  previousPage: () => void;
  /** Change page size and reset to first page */
  setPageSize: (pageSize: number) => void;
}

Custom Pagination Component:

function CustomPagination({
  canPreviousPage,
  canNextPage,
  pageOptions,
  pageCount,
  gotoPage,
  nextPage,
  previousPage,
  setPageSize,
  pageIndex,
  pageSize,
}) {
  return (
    <div className="pagination">
      <div className="pagination-info">
        Showing page {pageIndex + 1} of {pageCount}
      </div>
      
      <div className="pagination-buttons">
        <button 
          onClick={() => gotoPage(0)} 
          disabled={!canPreviousPage}
          title="First page"
        >
          ⏮
        </button>
        <button 
          onClick={previousPage} 
          disabled={!canPreviousPage}
          title="Previous page"
        >
          ⏪
        </button>
        
        {/* Page number buttons */}
        {pageOptions.slice(
          Math.max(0, pageIndex - 2),
          Math.min(pageCount, pageIndex + 3)
        ).map(page => (
          <button
            key={page}
            onClick={() => gotoPage(page)}
            className={pageIndex === page ? 'active' : ''}
          >
            {page + 1}
          </button>
        ))}
        
        <button 
          onClick={nextPage} 
          disabled={!canNextPage}
          title="Next page"
        >
          ⏩
        </button>
        <button 
          onClick={() => gotoPage(pageCount - 1)} 
          disabled={!canNextPage}
          title="Last page"
        >
          ⏭
        </button>
      </div>
      
      <div className="page-size-selector">
        <label>
          Rows per page:
          <select
            value={pageSize}
            onChange={e => setPageSize(Number(e.target.value))}
          >
            {[5, 10, 20, 30, 40, 50, 100].map(size => (
              <option key={size} value={size}>
                {size}
              </option>
            ))}
          </select>
        </label>
      </div>
    </div>
  );
}

Types

interface TableState {
  /** Current page index (0-based) */
  pageIndex: number;
  /** Number of rows per page */
  pageSize: number;
}

interface PaginationMeta {
  instance: TableInstance;
}

Install with Tessl CLI

npx tessl i tessl/npm-react-table

docs

built-in-types.md

column-management.md

core-table.md

filtering.md

grouping.md

index.md

layout.md

pagination.md

row-features.md

sorting.md

utilities.md

tile.json