React Bootstrap Pagination
React Bootstrap pagination driven by state: a current page, Previous and Next buttons that disable at the ends, and a table that shows one page of rows.
This component is only available in AdminKit PRO. Learn more.
When a list is too long for one screen, pagination splits it into pages and lets people move between them. They see where they are, jump to a page by its number, or step through with Previous and Next. Use it below a table of orders, a list of search results or a grid of cards.
In AdminKit for React, pagination is Bootstrap's markup written in JSX. There is no component to import. You keep the current page in React state and render one item per page, with the current one marked active. Pagination is part of AdminKit PRO: the stylesheet of the free version leaves out Bootstrap's pagination styles.
Example
This Pagination component renders the pager and nothing else. The parent holds the current page and passes it in, with a function to call when the user picks another page. Previous is disabled on the first page and Next on the last.
type PaginationProps = {
page: number;
pageCount: number;
onPageChange: (page: number) => void;
label: string;
};
export function Pagination({ page, pageCount, onPageChange, label }: PaginationProps) {
const pages = Array.from({ length: pageCount }, (_, index) => index + 1);
const isFirst = page === 1;
const isLast = page === pageCount;
return (
<nav aria-label={label}>
<ul className="pagination">
<li className={`page-item${isFirst ? " disabled" : ""}`}>
<button
type="button"
className="page-link"
disabled={isFirst}
onClick={() => onPageChange(page - 1)}
>
Previous
</button>
</li>
{pages.map((number) => (
<li
key={number}
className={`page-item${number === page ? " active" : ""}`}
aria-current={number === page ? "page" : undefined}
>
<button type="button" className="page-link" onClick={() => onPageChange(number)}>
{number}
</button>
</li>
))}
<li className={`page-item${isLast ? " disabled" : ""}`}>
<button
type="button"
className="page-link"
disabled={isLast}
onClick={() => onPageChange(page + 1)}
>
Next
</button>
</li>
</ul>
</nav>
);
}The items are buttons because they change state on this page. When each page has its own URL, use React Router Links with the page-link class instead.
Classes
| Class | Element | Effect |
|---|---|---|
pagination | <ul> | Joins the items into one row of connected boxes |
page-item | <li> | One item |
page-link | <button> or <a> | The box people click |
active | .page-item | Marks the current page in the primary color; add aria-current="page" too |
disabled | .page-item | Greys out an item and ignores clicks; also set disabled on the button |
pagination-sm, pagination-lg | .pagination | Smaller or larger items |
AdminKit makes Bootstrap's pagination a little more compact. In src/scss/1-variables/_app.scss, it sets the padding of the items to 0.3rem 0.75rem (0.15rem 0.6rem small, 0.35rem 1rem large). The items take the background of cards, in light and dark mode. Their text is --bs-gray-600, and --bs-gray-800 on hover. src/scss/3-components/_pagination.scss keeps the number of the active page white.
Pagination with a table
The most common use: a table that shows one page of rows at a time. Keep the current page in state, cut that page out of the rows with slice, and put the pager below the table. Here the rows come in as a prop:
import { useState } from "react";
import { Pagination } from "@/components/pagination";
type Order = { id: string; customer: string; total: string };
const pageSize = 10;
export function OrdersTable({ orders }: { orders: Order[] }) {
const [page, setPage] = useState(1);
const pageCount = Math.max(1, Math.ceil(orders.length / pageSize));
const rows = orders.slice((page - 1) * pageSize, page * pageSize);
return (
<div className="card">
<div className="card-body">
<table className="table table-striped">
<thead>
<tr>
<th>Order</th>
<th>Customer</th>
<th className="text-end">Total</th>
</tr>
</thead>
<tbody>
{rows.map((order) => (
<tr key={order.id}>
<td>{order.id}</td>
<td>{order.customer}</td>
<td className="text-end">{order.total}</td>
</tr>
))}
</tbody>
</table>
<Pagination
page={page}
pageCount={pageCount}
onPageChange={setPage}
label="Orders pages"
/>
</div>
</div>
);
}Tables has more on the table markup. If people also need to search and sort the rows, use the Data table plugin instead. It brings its own pager and draws it with the same pagination, page-item and page-link classes, so it looks the same as yours.
Sizes and alignment
On a busy card, a smaller pager takes less room. Add pagination-sm or pagination-lg to the list. To move the pager, use flexbox utilities such as justify-content-center or justify-content-end:
<nav aria-label="Invoices pages">
<ul className="pagination pagination-sm justify-content-end">
<li className="page-item active" aria-current="page">
<button type="button" className="page-link">1</button>
</li>
<li className="page-item">
<button type="button" className="page-link">2</button>
</li>
<li className="page-item">
<button type="button" className="page-link">3</button>
</li>
</ul>
</nav>Accessibility
- Wrap the list in a
<nav>with anaria-labelthat says what it pages through, such as "Orders pages". A page often has more than one navigation region. - Give the current page
aria-current="page". Theactiveclass only changes its color. - Set
disabledon the button of a disabled item. Then Tab skips it and a click does nothing. With an<a>, thedisabledclass alone does not stop the keyboard: addtabIndex={-1}andaria-disabled="true". - When Previous and Next show only an icon, give the button an
aria-label, as the demo does.
Related
- Next.js Bootstrap pagination: the same markup in AdminKit for Next.js
- Bootstrap 5 pagination: the pagination of the HTML version
- Tables: the table markup to page through
- Data table: search, sorting and a built-in pager
- General UI demo: pagination in three sizes, breadcrumbs and other Bootstrap components
Last updated on
BreadcrumbPro
A React Bootstrap breadcrumb in JSX: show where a page sits in your app, with React Router links built from the current route and custom dividers.
Form control
React Bootstrap form controls in AdminKit: inputs and textareas as plain Bootstrap markup in JSX, with sizes, disabled and read-only states, controlled or not.