Installation
Install the dependencies
pnpm add cn class-variance-authority github:sveltery/baseCopy the component
Copy the following files into src/lib/components/ui/pagination.
It imports the button component, so copy its folder too.
<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><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><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><script lang="ts">
import type { PaginationItemProps } from './types.js';
let { children, ...props }: PaginationItemProps = $props();
</script>
<li data-slot="pagination-item" {...props}>
{@render children?.()}
</li><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><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><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>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>;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>