Skip to content
    Style: Wireframe

    Blocks · Navigation

    Numbered pagination

    Previous and next with icons, page numbers with a gap, the current page marked and the ends disabled, with a line about what is shown.

    38% of the 2,073 sites in The UI Index have a navigation (790 sites).

    Showing 41 to 50 of 118 posts

    Showing 1 to 10 of 118 posts

    Showing 111 to 118 of 118 posts

    Both previews render the same markup; the HTML tab below is that markup without a framework.

    Install

    React
    npx shadcn@latest add https://www.themes.dev/ui/r/numbered-pagination.json
    Astro
    npx shadcn@latest add https://www.themes.dev/ui/r/astro/numbered-pagination.json

    Or copy the files below into your project. They need clsx, tailwind-merge and the components they import, and the themes.dev UI theme. The HTML needs only the compiled CSS.

    numbered-pagination.classes.ts
    /** Numbered pagination as a section: previous and next with icons, the page numbers with a gap (…) where pages are
     *  skipped, the current page marked (aria-current) and the ends disabled. The links are the pagination item; this
     *  adds the row with a short line about what is on the page. Narrow rows swap the numbers for 'Page 5 of 12'. */
    export const numberedPagination = {
      root: 'mx-auto flex w-full max-w-6xl flex-col gap-3 px-6 py-6 @container',
      summary: 'm-0 text-sm text-muted-foreground tabular-nums',
      nav: 'w-full',
    };
    numbered-pagination.tsx
    import { Pagination } from '@/components/ui/pagination';
    import { cn } from '@/lib/utils';
    import { numberedPagination as c } from './numbered-pagination.classes';
    
    export interface NumberedPaginationProps {
      current: number;
      total: number;
      /** The address of a page, e.g. (p) => `/blog/page/${p}/`. */
      href: (page: number) => string;
      /** The accessible name of the nav; give each pager on a page its own. */
      label?: string;
      /** A line before the pages, e.g. "Showing 41 to 50 of 118 posts". */
      summary?: string;
      className?: string;
    }
    
    export function NumberedPagination({ current, total, href, label = 'Pages', summary, className }: NumberedPaginationProps) {
      return (
        <div className={cn(c.root, className)}>
          {summary && <p className={c.summary}>{summary}</p>}
          <Pagination current={current} total={total} href={href} label={label} className={c.nav} />
        </div>
      );
    }