ComponentsP3 본문

Pagination

페이지 내비게이션 — 비제어(defaultPage) + onPageChange 알림. 줄임 로직(1 … 9 10 11 … 20), 경계에서 이전/다음 disabled.

마지막 업데이트 2026-06-11

한눈에#

목록·검색 결과를 페이지 단위로 끊어 이동하는 내비게이션입니다 — 현재 페이지 ±1과 양끝만 남기고 사이를 줄임표(…)로 접습니다.

  • 줄임 로직(1 … 9 10 11 … 20)
  • 비제어 + onPageChange
  • numeric·dots
  • 44px 히트 영역

경계에서 이전/다음이 자동 비활성 — 현재 페이지는 aria-current=page

직접 클릭해 보세요 — 현재 페이지 ±1과 양끝(1, 20)만 남기고 사이를 줄임표(…)로 접습니다.

사용 시점#

목록·검색 결과를 페이지 단위로 끊어 이동하면 Pagination — 편집·정렬이 있는 운영 표는 DataGrid가 합성합니다.

권장 — 이렇게 쓰세요

지양 — 이러지 마세요

쓴다목록·검색 결과를 페이지 단위로 끊어 이동(URL이 진실의 원천이면 page로 제어)

대신 DataGrid편집·정렬이 있는 운영 표 — pageSize로 Pagination을 합성

플레이그라운드#

컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

Pagination를 직접 조작해 보세요

속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.

빌더 열기

플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.

변형#

페이지가 적으면 전체 표시 — 줄임 없음

비제어(defaultPage)와 제어(page)를 모두 지원합니다. 비제어는 현재 페이지를 내부에서 소유하고 변경만 알립니다. URL이 진실의 원천이어야 하는 경우 page로 제어하세요 — 클릭은 onPageChange로만 통지하고 현재 페이지는 외부 값을 따릅니다(함수 prop은 서버 MDX로 전달 불가라 코드로 보입니다):

'use client';

// 비제어 — 컴포넌트가 페이지를 소유, 라우터는 부수효과
function ProductListPagination({ totalPages }: { totalPages: number }) {
  const router = useRouter();
  return (
    <Pagination
      totalPages={totalPages}
      defaultPage={1}
      onPageChange={(page) => router.push(`?page=${page}`)}
    />
  );
}

// 제어 — URL search param이 진실의 원천(page가 권위)
function ControlledPagination({ totalPages }: { totalPages: number }) {
  const params = useSearchParams();
  const router = useRouter();
  const page = Number(params.get('page') ?? 1);
  return (
    <Pagination
      totalPages={totalPages}
      page={page}
      onPageChange={(next) => router.push(`?page=${next}`)}
    />
  );
}

크기#

size prop이 없습니다 — 버튼은 시각 32px 정사각형(space.8)에 44px 히트 영역이 확장된 단일 크기입니다.

상태#

  • 현재 페이지primary-subtle 배경 + primary-text + semibold (aria-current="page")
  • 경계 disabled — 1페이지에서 이전, 마지막에서 다음 버튼이 비활성
  • hoversurface-hover 배경, focus — 2px focus-ring
  • 이미 현재인 페이지를 클릭하면 onPageChange가 호출되지 않습니다

Props#

Prop타입기본값설명
totalPagesnumber전체 페이지 수 (1 이상)
pagenumber제어 현재 페이지 — 제공하면 제어 모드(내부 상태 무시, 전환은 onPageChange로만 통지)
defaultPagenumber1초기 현재 페이지 (비제어, page 미제공 시, 기본 1)
onPageChange(page: number) => void페이지 변경 알림 — 제어/비제어 모두에서 호출
labelstring페이지네이션nav aria-label (기본 '페이지네이션')
previousLabelstring이전 페이지이전 버튼 aria-label (기본 '이전 페이지')
nextLabelstring다음 페이지다음 버튼 aria-label (기본 '다음 페이지')
variant'numeric' | 'dots'numericnumeric(기본): 숫자 버튼+줄임 · dots: 점 페이지 컨트롤(소량 페이지·모바일, ADR-012 B-P1)
refRef<HTMLElement>루트 <nav>로 전달되는 ref (React 19 ref-as-prop)

접근성#

  • <nav aria-label="페이지네이션"> + ul/li — 랜드마크로 점프 가능합니다
  • 현재 페이지는 aria-current="page", 각 페이지 버튼은 aria-label="N 페이지"
  • 이전/다음은 아이콘 버튼이라 previousLabel/nextLabel이 접근성 이름입니다
  • 줄임표(…)는 장식(aria-hidden) — 낭독되지 않습니다
  • 경계 비활성은 disabled 속성 — 포커스 순서에서 자연스럽게 제외됩니다

토큰#

component 토큰 없이 semantic을 직접 소비합니다(신설 기준 §4 미충족).

속성토큰
버튼 기본color.text-muted · font-size.body-2 + font-weight.medium
버튼 hovercolor.surface-hover + color.text
버튼 눌림(:active)color.surface-pressed (현재 페이지는 유지)
현재 페이지color.primary-subtle + color.primary-text + font-weight.semibold
disabledcolor.text-placeholder
줄임표color.text-placeholder
형태space.8(32px 셀) · space.1/2 · radius.md · icon.size-md
모션duration.fast + ease.standard