Pagination

Pagination with page navigation, next and previous links.

Basic
Simple
With Select

Installation

Install the dependencies

pnpm add cn class-variance-authority github:sveltery/base

Copy the component

Copy the following files into src/lib/components/ui/pagination.

It imports the button component, so copy its folder too.

src/lib/components/ui/pagination/Pagination.svelte
<script lang="ts">
  import type { PaginationProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: PaginationProps = $props();
</script>
<!-- svelte-ignore a11y_no_redundant_roles -->
<nav role="navigation" aria-label="pagination" data-slot="pagination" {...props} class={cn('mx-auto flex w-full justify-center', classProp)}>
  {@render children?.()}
</nav>
src/lib/components/ui/pagination/PaginationContent.svelte
<script lang="ts">
  import type { PaginationContentProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: PaginationContentProps = $props();
</script>
<ul data-slot="pagination-content" {...props} class={cn('gap-0.5 flex items-center', classProp)}>
  {@render children?.()}
</ul>
src/lib/components/ui/pagination/PaginationEllipsis.svelte
<script lang="ts">
  import type { PaginationEllipsisProps } from './types.js';
  import { cn } from 'cn';
  import MoreHorizontalIcon from '@lucide/svelte/icons/more-horizontal';
  let { class: classProp, ...props }: PaginationEllipsisProps = $props();
</script>
<span aria-hidden="true" data-slot="pagination-ellipsis" {...props} class={cn("size-8 [&_svg:not([class*='size-'])]:size-4 flex items-center justify-center", classProp)}>
  <MoreHorizontalIcon
  />
  <span class="sr-only">More pages</span>
</span>
src/lib/components/ui/pagination/PaginationItem.svelte
<script lang="ts">
  import type { PaginationItemProps } from './types.js';
  let { children, ...props }: PaginationItemProps = $props();
</script>
<li data-slot="pagination-item" {...props}>
  {@render children?.()}
</li>
src/lib/components/ui/pagination/PaginationLink.svelte
<script lang="ts">
  import type { PaginationLinkProps } from './types.js';
  import { cn } from 'cn';
  import { Button } from '../button/index.js';
  let { children, class: classProp, isActive, size = 'icon', ...props }: PaginationLinkProps = $props();
</script>
<Button variant={isActive ? 'outline' : 'ghost'} {size} class={cn('', classProp)} nativeButton={false} {...props}>
  {#snippet render(buttonProps)}
    <a {...buttonProps} aria-current={isActive ? 'page' : undefined} data-slot="pagination-link" data-active={isActive}>
      {@render children?.()}
    </a>
  {/snippet}
</Button>
src/lib/components/ui/pagination/PaginationNext.svelte
<script lang="ts">
  import type { PaginationNextProps } from './types.js';
  import { cn } from 'cn';
  import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
  import PaginationLink from './PaginationLink.svelte';
  let { class: classProp, text = 'Next', ...props }: PaginationNextProps = $props();
</script>
<PaginationLink aria-label="Go to next page" size="default" {...props} class={cn('pr-1.5!', classProp)}>
  <span class="hidden sm:block">{text}</span>
  <ChevronRightIcon
    data-icon="inline-end"
    class=""
  />
</PaginationLink>
src/lib/components/ui/pagination/PaginationPrevious.svelte
<script lang="ts">
  import type { PaginationPreviousProps } from './types.js';
  import { cn } from 'cn';
  import ChevronLeftIcon from '@lucide/svelte/icons/chevron-left';
  import PaginationLink from './PaginationLink.svelte';
  let { class: classProp, text = 'Previous', ...props }: PaginationPreviousProps = $props();
</script>
<PaginationLink aria-label="Go to previous page" size="default" {...props} class={cn('pl-1.5!', classProp)}>
  <ChevronLeftIcon
    data-icon="inline-start"
    class=""
  />
  <span class="hidden sm:block">{text}</span>
</PaginationLink>
src/lib/components/ui/pagination/types.ts
import type { HTMLAnchorAttributes, HTMLAttributes, HTMLLiAttributes } from 'svelte/elements';
import type { ButtonProps } from '../button/index.js';

export type PaginationProps = HTMLAttributes<HTMLElement>;
export type PaginationContentProps = HTMLAttributes<HTMLUListElement>;
export type PaginationItemProps = HTMLLiAttributes;
// Base's Button types its own props for a native button. The link attributes come from the anchor.
export type PaginationLinkProps = Omit<ButtonProps, 'variant' | 'nativeButton' | 'render'> & Pick<HTMLAnchorAttributes, 'href' | 'hreflang' | 'target' | 'rel' | 'download'> & { isActive?: boolean };
export type PaginationPreviousProps = Omit<PaginationLinkProps, 'children'> & { text?: string };
export type PaginationNextProps = Omit<PaginationLinkProps, 'children'> & { text?: string };
export type PaginationEllipsisProps = HTMLAttributes<HTMLSpanElement>;
src/lib/components/ui/pagination/index.ts
export { default as Pagination } from './Pagination.svelte';
export { default as PaginationContent } from './PaginationContent.svelte';
export { default as PaginationItem } from './PaginationItem.svelte';
export { default as PaginationLink } from './PaginationLink.svelte';
export { default as PaginationPrevious } from './PaginationPrevious.svelte';
export { default as PaginationNext } from './PaginationNext.svelte';
export { default as PaginationEllipsis } from './PaginationEllipsis.svelte';
export type {
  PaginationProps, PaginationContentProps, PaginationItemProps, PaginationLinkProps,
  PaginationPreviousProps, PaginationNextProps, PaginationEllipsisProps,
} from './types.js';

Update the import paths

Change the imports to match your project setup.

Usage

<script lang="ts">
  import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from '$lib/components/ui/pagination';
</script>
<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious href="?page=1" />
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="?page=1">1</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="?page=2" isActive>2</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationEllipsis />
    </PaginationItem>
    <PaginationItem>
      <PaginationNext href="?page=3" />
    </PaginationItem>
  </PaginationContent>
</Pagination>