gnome-ui
Components

Pagination

A pagination component for navigating between pages of content. Composed of `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationButton`, `PaginationPrevious`, `PaginationNext`, and `PaginationEllipsis`.

Pagination component
import * as React from 'react';
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationButton,
  PaginationPrevious,
  PaginationNext,
  PaginationEllipsis,
} from 'gnome-ui/pagination';

function PaginationDefault() {
  const [page, setPage] = React.useState(1);
  const total = 10;

  const getVisiblePages = (): (number | 'ellipsis')[] => {
    const pages: (number | 'ellipsis')[] = [];
    pages.push(1);
    if (page > 3) pages.push('ellipsis');
    for (
      let i = Math.max(2, page - 1);
      i <= Math.min(total - 1, page + 1);
      i++
    ) {
      pages.push(i);
    }
    if (page < total - 2) pages.push('ellipsis');
    if (total > 1) pages.push(total);
    return pages;
  };

  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious
            onClick={() => setPage((p) => Math.max(1, p - 1))}
            disabled={page === 1}
          />
        </PaginationItem>

        {getVisiblePages().map((p, i) =>
          p === 'ellipsis' ? (
            <PaginationItem key={`e-${i}`}>
              <PaginationEllipsis />
            </PaginationItem>
          ) : (
            <PaginationItem key={p}>
              <PaginationButton active={page === p} onClick={() => setPage(p)}>
                {p}
              </PaginationButton>
            </PaginationItem>
          )
        )}

        <PaginationItem>
          <PaginationNext
            onClick={() => setPage((p) => Math.min(total, p + 1))}
            disabled={page === total}
          />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}

Anatomy

import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationButton,
  PaginationPrevious,
  PaginationNext,
  PaginationEllipsis,
} from 'gnome-ui/pagination';

<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious />
    </PaginationItem>
    <PaginationItem>
      <PaginationButton active>1</PaginationButton>
    </PaginationItem>
    <PaginationItem>
      <PaginationNext />
    </PaginationItem>
  </PaginationContent>
</Pagination>

Examples

Compact

Minimal previous/next layout with a page counter — useful for mobile or narrow spaces.

Pagination component
Page 3 of 20
import * as React from 'react';
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationPrevious,
  PaginationNext,
} from 'gnome-ui/pagination';

function PaginationCompact() {
  const [page, setPage] = React.useState(3);
  const total = 20;

  return (
    <div className="flex items-center gap-4">
      <Pagination>
        <PaginationContent>
          <PaginationItem>
            <PaginationPrevious
              onClick={() => setPage((p) => Math.max(1, p - 1))}
              disabled={page === 1}
            />
          </PaginationItem>
          <PaginationItem>
            <PaginationNext
              onClick={() => setPage((p) => Math.min(total, p + 1))}
              disabled={page === total}
            />
          </PaginationItem>
        </PaginationContent>
      </Pagination>
      <span className="text-sm text-muted-foreground">
        Page {page} of {total}
      </span>
    </div>
  );
}

Full with Smart Ellipsis

Automatically shows a window of pages around the current one, with ellipsis for hidden ranges.

Pagination component
import * as React from 'react';
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationButton,
  PaginationPrevious,
  PaginationNext,
  PaginationEllipsis,
} from 'gnome-ui/pagination';

function PaginationFull() {
  const [page, setPage] = React.useState(5);
  const total = 20;

  const getVisiblePages = () => {
    const pages: (number | 'ellipsis')[] = [];
    pages.push(1);
    if (page > 3) pages.push('ellipsis');
    for (
      let i = Math.max(2, page - 1);
      i <= Math.min(total - 1, page + 1);
      i++
    ) {
      pages.push(i);
    }
    if (page < total - 2) pages.push('ellipsis');
    if (total > 1) pages.push(total);
    return pages;
  };

  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious
            onClick={() => setPage((p) => Math.max(1, p - 1))}
            disabled={page === 1}
          />
        </PaginationItem>

        {getVisiblePages().map((p, i) =>
          p === 'ellipsis' ? (
            <PaginationItem key={`e-${i}`}>
              <PaginationEllipsis />
            </PaginationItem>
          ) : (
            <PaginationItem key={p}>
              <PaginationButton active={page === p} onClick={() => setPage(p)}>
                {p}
              </PaginationButton>
            </PaginationItem>
          )
        )}

        <PaginationItem>
          <PaginationNext
            onClick={() => setPage((p) => Math.min(total, p + 1))}
            disabled={page === total}
          />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}

Props — PaginationButton

PropTypeDefaultDescription
activebooleanfalseHighlights the button as the current page.
disabledbooleanfalseDisables interaction.
onClick() => voidClick handler.
classNamestringAdditional CSS classes.
childrenReactNodePage number or label.

Props — PaginationPrevious / PaginationNext

PropTypeDefaultDescription
disabledbooleanfalseDisables the button when at the boundary.
onClick() => voidClick handler.

On this page