Pagination

Pagination

활성 페이지를 표시하고 여러 페이지 사이를 탐색하는 컴포넌트예요.

출처: 문서

본문

사용법 (Usage)

Pagination으로 활성 페이지를 표시하고 여러 페이지 사이를 탐색할 수 있어요. total, color, size, radius, withControls, withEdges, disabled 등의 prop을 지원해요.

import { Pagination } from '@mantine/core';

function Demo() {
  return <Pagination total={10} />;
}

청크 콘텐츠 예시 (Example with chunked content)

데이터를 페이지 크기로 나눠 Pagination과 함께 사용하는 예시예요.

import { useState } from 'react';
import { randomId } from '@mantine/hooks';
import { Pagination, Text } from '@mantine/core';

function chunk<T>(array: T[], size: number): T[][] {
  if (!array.length) {
    return [];
  }
  const head = array.slice(0, size);
  const tail = array.slice(size);
  return [head, ...chunk(tail, size)];
}

const data = chunk(
  Array(30)
    .fill(0)
    .map((_, index) => ({ id: index, name: randomId() })),
  5
);

function Demo() {
  const [activePage, setPage] = useState(1);
  const items = data[activePage - 1].map((item) => (
    <Text key={item.id}>id: {item.id}, name: {item.name}</Text>
  ));

  return (
    <>
      {items}
      <Pagination total={data.length} value={activePage} onChange={setPage} mt="sm" />
    </>
  );
}

제어 방식 (Controlled)

컴포넌트 상태를 제어하려면 value와 onChange prop을 제공해요.

import { useState } from 'react';
import { Pagination } from '@mantine/core';

function Demo() {
  const [activePage, setPage] = useState(1);
  return <Pagination value={activePage} onChange={setPage} total={10} />;
}

형제 수 (Siblings)

siblings prop으로 활성 항목 형제의 수를 제어해요.

import { Text, Pagination } from '@mantine/core';

function Demo() {
  return (
    <>
      <Text>1 sibling (default)</Text>
      <Pagination total={20} siblings={1} />
      <Text>2 siblings</Text>
      <Pagination total={20} siblings={2} />
      <Text>3 siblings</Text>
      <Pagination total={20} siblings={3} />
    </>
  );
}

경계 수 (Boundaries)

boundaries prop으로 이전 버튼 뒤와 다음 버튼 앞에 표시할 항목 수를 제어해요.

import { Text, Pagination } from '@mantine/core';

function Demo() {
  return (
    <>
      <Text>1 boundary (default)</Text>
      <Pagination total={20} boundaries={1} />
      <Text>2 boundaries</Text>
      <Pagination total={20} boundaries={2} />
      <Text>3 boundaries</Text>
      <Pagination total={20} boundaries={3} />
    </>
  );
}

반응형 레이아웃 (Responsive layout)

layout="responsive"로 설정하면 CSS 컨테이너 쿼리를 사용해 컨테이너가 좁을 때 컴팩트한 "Page X of Y" 라벨을 표시할 수 있어요. formatLabel prop으로 라벨 텍스트를 커스터마이즈해요.

import { Box, Pagination } from '@mantine/core';

function Demo() {
  return (
    <Box w={200}>
      <Pagination total={20} layout="responsive" />
    </Box>
  );
}

페이지 컨트롤 숨기기 (Hide pages controls)

withPages={false}로 설정하면 페이지 컨트롤을 숨길 수 있어요.

import { useState } from 'react';
import { Group, Pagination, Text } from '@mantine/core';

const limit = 10;
const total = 145;
const totalPages = Math.ceil(total / limit);

function Demo() {
  const [page, setPage] = useState(1);
  const message = `Showing ${limit * (page - 1) + 1} – ${Math.min(total, limit * page)} of ${total}`;

  return (
    <Group justify="space-between">
      <Text>{message}</Text>
      <Pagination total={totalPages} value={page} onChange={setPage} withPages={false} />
    </Group>
  );
}

Styles API

Pagination은 Styles API를 지원해요. classNames prop으로 컴포넌트의 내부 요소에 스타일을 추가할 수 있어요.

Styles API 셀렉터:

  • root – 루트 요소
  • control – 컨트롤 요소: 항목, 다음/이전, 처음/마지막 버튼
  • dots – 점 아이콘 래퍼
  • items – 페이지 번호 컨트롤 주변 래퍼, layout="responsive"와 함께 사용
  • label – layout="responsive"에서 좁은 컨테이너에 표시되는 컴팩트 라벨 요소

복합 컴포넌트 (Compound components)

Pagination 렌더링을 완전히 제어하려면 다음 복합 컴포넌트를 사용할 수 있어요.

  • Pagination.Root – 컨텍스트 제공자
  • Pagination.Items – 항목 목록
  • Pagination.Next – 다음 컨트롤
  • Pagination.Previous – 이전 컨트롤
  • Pagination.First – 처음 컨트롤
  • Pagination.Last – 마지막 컨트롤
  • Pagination.Label – 반응형 레이아웃용 컴팩트 라벨
import { Group, Pagination } from '@mantine/core';

function Demo() {
  return (
    <Pagination.Root total={10}>
      <Group gap={7}>
        <Pagination.First />
        <Pagination.Previous />
        <Pagination.Items />
        <Pagination.Next />
        <Pagination.Last />
      </Group>
    </Pagination.Root>
  );
}

getItemProps와 getControlProps로 컨트롤을 링크로 렌더링할 수 있어요.

import { Group, Pagination } from '@mantine/core';

function Demo() {
  return (
    <>
      {/* Regular pagination */}
      <Pagination
        total={10}
        getItemProps={(page) => ({ component: 'a', href: `#page-${page}` })}
        getControlProps={(control) => {
          if (control === 'first') return { component: 'a', href: '#page-0' };
          if (control === 'last') return { component: 'a', href: '#page-10' };
          if (control === 'next') return { component: 'a', href: '#page-2' };
          if (control === 'previous') return { component: 'a', href: '#page-1' };
          return {};
        }}
      />
    </>
  );
}

아이콘 변경 (Change icons)

icons prop으로 이전/다음/처음/마지막/점 아이콘을 변경할 수 있어요.

import { Group, Pagination } from '@mantine/core';
import { ArrowLineRightIcon, ArrowLineLeftIcon, ArrowLeftIcon, ArrowRightIcon, DotsSixIcon } from '@phosphor-icons/react';

function Demo() {
  return (
    <Pagination
      total={10}
      icons={{
        first: <ArrowLineLeftIcon size={16} />,
        last: <ArrowLineRightIcon size={16} />,
        next: <ArrowRightIcon size={16} />,
        previous: <ArrowLeftIcon size={16} />,
        dots: <DotsSixIcon size={16} />,
      }}
    />
  );
}

autoContrast

Pagination은 autoContrast prop과 theme.autoContrast를 지원해요. Pagination 또는 테마에 autoContrast가 설정되면 color prop에 지정된 값과 충분한 대비가 있도록 콘텐츠 색상이 조정돼요.

autoContrast 기능은 color prop으로 배경색을 변경할 때만 동작해요.

import { Pagination, Stack, Text } from '@mantine/core';

function Demo() {
  return (
    <Stack>
      <Text>autoContrast: off</Text>
      <Pagination total={10} color="red" />
      <Text>autoContrast: on</Text>
      <Pagination total={10} color="red" autoContrast />
    </Stack>
  );
}

컨트롤 크기 (Controls size)

기본적으로 페이지네이션 컨트롤은 인풋과 버튼보다 작은 크기를 가져요. 컨트롤을 인풋·버튼과 같은 크기로 만들려면 size prop에 input- 접두사를 사용할 수 있어요.

import { Button, Group, Pagination, TextInput } from '@mantine/core';

function Demo() {
  return (
    <Group>
      <TextInput size="sm" placeholder="sm input" />
      <Button size="sm">sm button</Button>
      <Pagination total={10} size="input-sm" />
    </Group>
  );
}

시작 값 (Start value)

startValue로 시작 페이지 번호를 정의할 수 있어요. 예를 들어 startValue={5}와 total={15}를 사용하면 페이지네이션 범위는 5부터 15까지예요.

import { Text, Pagination } from '@mantine/core';

function Demo() {
  return (
    <>
      <Text>Pages 5–15 (startValue=5, total=15)</Text>
      <Pagination startValue={5} total={15} />
    </>
  );
}

URL 동기화 (URL synchronization)

페이지네이션 상태를 URL 쿼리 매개변수와 동기화할 수 있어요. 이 패턴은 특정 페이지가 선택된 URL을 공유하고 싶은 목록 뷰에서 흔히 사용돼요.

Next.js

import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { Pagination } from '@mantine/core';

function Demo() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const pathname = usePathname();
  const page = Number(searchParams.get('page')) || 1;

  const handlePageChange = (p: number) => {
    const params = new URLSearchParams(searchParams);
    params.set('page', p.toString());
    router.push(`${pathname}?${params.toString()}`);
  };

  return <Pagination total={10} value={page} onChange={handlePageChange} />;
}

react-router-dom

import { useSearchParams } from 'react-router-dom';
import { Pagination } from '@mantine/core';

function Demo() {
  const [searchParams, setSearchParams] = useSearchParams();
  const page = Number(searchParams.get('page')) || 1;

  const handlePageChange = (p: number) => {
    setSearchParams({ page: p.toString() });
  };

  return <Pagination total={10} value={page} onChange={handlePageChange} />;
}

nuqs

nuqs를 사용하는 예시:

import { useQueryState, parseAsInteger } from 'nuqs';
import { Pagination } from '@mantine/core';

function Demo() {
  const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1));
  return <Pagination total={10} value={page} onChange={setPage} />;
}

use-pagination 훅

더 많은 유연성이 필요하다면 @mantine/hooks 패키지가 use-pagination 훅을 내보내요. 커스텀 페이지네이션 컴포넌트를 만드는 데 사용할 수 있어요.

더 알아보기 (Learn more)