Pagination | CoUI

Pagination

대용량 콘텐츠를 여러 페이지로 나누어 탐색하는 페이지네이션 컴포넌트

Pagination#

대용량 콘텐츠를 페이지 단위로 나누어 탐색할 수 있는 컴포넌트입니다. 현재 페이지 표시, 이전/다음 이동, 첫/마지막 페이지 이동을 지원합니다.

Live Preview#

Web
Flutter
Loading Flutter...
class PaginationDefaultExample extends StatefulComponent {
  const PaginationDefaultExample({super.key});

  @override
  State<PaginationDefaultExample> createState() =>
      _PaginationDefaultExampleState();
}

class _PaginationDefaultExampleState extends State<PaginationDefaultExample> {
  int _page = 3;

  @override
  Component build(BuildContext context) {
    return Pagination(
      page: _page,
      totalPages: 10,
      onPageChanged: (value) => setState(() => _page = value),
    );
  }
}
class PaginationDefaultExample extends StatefulWidget {
  const PaginationDefaultExample({super.key});

  @override
  State<PaginationDefaultExample> createState() =>
      _PaginationDefaultExampleState();
}

class _PaginationDefaultExampleState extends State<PaginationDefaultExample> {
  int _page = 3;

  @override
  Widget build(BuildContext context) {
    return Pagination(
      page: _page,
      totalPages: 10,
      onPageChanged: (p) => setState(() => _page = p),
    );
  }
}

사용 시기 (When to Use)#

이 컴포넌트를 사용하세요:

  • 테이블, 검색 결과, 상품 목록처럼 많은 데이터를 페이지 단위로 나눠 표시할 때
  • 사용자가 특정 페이지로 직접 이동할 수 있어야 할 때
  • 전체 데이터 양이 많지 않아 페이지 번호로 탐색이 유용한 경우

대신 다른 컴포넌트를 사용하세요:

  • RefreshTrigger: 무한 스크롤 방식으로 데이터를 로드할 때
  • Select: 페이지 크기 선택 등 드롭다운 옵션이 필요할 때

기본 사용법 (Basic Usage)#

Flutter / Web 모두 동일한 Pagination API 를 사용합니다.

// 기본 페이지네이션
Pagination(
  page: _currentPage,
  totalPages: 10,
  onPageChanged: handlePageChanged,
)

// 더 넓은 페이지 범위 + prev/next 라벨
Pagination(
  page: _currentPage,
  totalPages: 20,
  onPageChanged: handlePageChanged,
  maxPages: 7,
  showLabel: true,
)

// 첫 페이지에서 이전 버튼 숨김
Pagination(
  page: _currentPage,
  totalPages: 5,
  onPageChanged: handlePageChanged,
  hidePreviousOnFirstPage: true,
)
// 기본 페이지네이션 (이전/다음 버튼 포함)
Pagination(
  page: currentPage,
  totalPages: 10,
  onPageChanged: handlePageChanged,
)

// 더 넓은 페이지 범위 + prev/next 라벨
Pagination(
  page: currentPage,
  totalPages: 20,
  onPageChanged: handlePageChanged,
  maxPages: 7,
  showLabel: true,
)

Props / Parameters#

속성타입기본값설명
pageint필수현재 페이지 (1-based)
totalPagesint필수전체 페이지 수
onPageChanged void Function(int)? null 페이지 변경 핸들러 (1-based)
maxPages int 3 표시할 최대 페이지 버튼 수
showSkipToFirstPage bool true 선행 생략 시 첫 페이지 이동 버튼 표시
showSkipToLastPage bool true 후행 생략 시 마지막 페이지 이동 버튼 표시
hidePreviousOnFirstPage bool false 첫 페이지에서 이전 버튼 숨김
hideNextOnLastPage bool false 마지막 페이지에서 다음 버튼 숨김
showLabel bool false 이전/다음 버튼에 텍스트 라벨 표시
variant CorePaginationVariant standard 시각 변형
paginationStyle CorePaginationStyle? null 인스턴스 스타일 (Style 시스템 참조)

스타일 시스템 (Style System)#

Pagination 의 모든 chrome / dimensional 오버라이드는 CorePaginationStyle 단일 슬롯으로 흐릅니다. behaviour 필드 (page / totalPages / onPageChanged / maxPages / showSkipToFirstPage / showSkipToLastPage / hidePreviousOnFirstPage / hideNextOnLastPage / showLabel) 는 위젯/컴포넌트 파라미터로 직접 전달합니다.

시맨틱 vs 스타일#

  • 시맨틱 / behaviour: 위젯/컴포넌트 파라미터로 직접 (page, totalPages, onPageChanged, maxPages, showSkipToFirstPage, showSkipToLastPage, hidePreviousOnFirstPage, hideNextOnLastPage, showLabel)
  • chrome / dimensional: CorePaginationStyle 한 곳으로

Resolve chain#

CorePaginationStyle.defaultX                   // design system default
  → CorePaginationTheme.style                  // 프로젝트 공통
  → widget.paginationStyle                     // 인스턴스별

필드 매핑 (CorePaginationStyle)#

필드타입적용 영역
itemSpacing double? 페이지네이션 버튼 간격 (logical px) — Row.spacing / CSS flex gap 으로 적용
buttonSizedouble?정사각형 버튼의 너비/높이 (logical px)
buttonRadiusCoreBorderRadius?버튼 모서리 반경
activeBackgroundColorCoreColor?활성(현재) 페이지 버튼 배경
activeForegroundColorCoreColor?활성(현재) 페이지 버튼 전경
hoverBackgroundColorCoreColor?호버 시 배경
hoverForegroundColorCoreColor?호버 시 전경
foregroundColorCoreColor?비활성/이전/다음 버튼 전경
ellipsisStyle CoreTextStyle? 생략 표시 () 텍스트 스타일

변형 (Variants)#

Pagination 은 현재 단일 시각 변형(standard) 을 가집니다. 표시되는 페이지 범위와 prev/next 라벨은 behaviour 파라미터로 조정합니다.

// 더 넓은 페이지 범위 + 라벨
Pagination(
  page: 5,
  totalPages: 20,
  onPageChanged: handlePageChanged,
  maxPages: 7,
  showLabel: true,
)

동작 스펙 (Behavior)#

인터랙션#

  • 페이지 버튼 클릭: 해당 페이지로 이동 (onPageChanged(page) 호출)
  • 이전/다음 버튼: 현재 페이지에서 1씩 감소/증가
  • 첫/마지막 버튼: 1페이지 또는 totalPages로 이동
  • 현재 페이지 버튼: 클릭해도 이벤트 없음 (비활성 강조)
  • 경계 버튼: 첫 페이지에서 이전 버튼, 마지막 페이지에서 다음 버튼은 비활성

상태 전환#

  • 현재 페이지 버튼: 강조 색상 + 비활성 클릭
  • 경계 도달 시 이전/다음 버튼 disabled 처리
  • 페이지 수가 많으면 현재 페이지 기준으로 중간 항목 ...으로 생략

애니메이션#

  • 페이지 전환 시 별도 애니메이션 없음 (콘텐츠 영역 전환은 부모가 처리)
  • 버튼 호버 시 배경색 200ms 전환

사용 가이드라인 (Usage Guidelines)#

✅ Do#

많은 데이터에는 skip-to-first / skip-to-last 버튼 활용

Pagination(
  page: _currentPage,
  totalPages: 50,
  onPageChanged: handlePageChanged,
  showSkipToFirstPage: true,
  showSkipToLastPage: true,
)

50페이지 이상의 데이터에서 첫/마지막 페이지 버튼은 멀리 있는 페이지로의 빠른 이동을 지원한다.


❌ Don't#

페이지가 1개일 때 Pagination 표시

// ❌ 페이지가 1개뿐인데 Pagination 표시
Pagination(
  page: 1,
  totalPages: 1,
  onPageChanged: handlePageChanged,
)

페이지가 1개뿐이면 Pagination이 의미 없고 오히려 혼란을 준다. totalPages > 1인 경우에만 표시한다.

✅ Do#

좁은 화면에서는 maxPages 를 작게 유지

Pagination(
  page: _currentPage,
  totalPages: 20,
  onPageChanged: handlePageChanged,
  maxPages: 3,
)

maxPages 가 크면 버튼이 너무 많아 모바일 화면에서 줄바꿈이 발생한다. 3~5가 적당하다.


❌ Don't#

데이터가 적을 때 불필요하게 페이지네이션을 표시하지 마세요.

// ❌ 한 페이지에 다 들어오는데도 표시
Pagination(
  page: 1,
  totalPages: 1,
  onPageChanged: handlePageChanged,
)

단일 페이지라면 페이지네이션은 불필요한 UI 요소입니다. 총 항목 수가 페이지당 개수보다 적으면 숨기세요.

접근성 (Accessibility)#

키보드 인터랙션#

동작
Tab다음 페이지 버튼으로 포커스
Enter / Space포커스된 페이지 버튼 활성화
Arrow Left/Right이전/다음 페이지 버튼으로 포커스 이동

스크린 리더#

  • Flutter: Semantics(label: '페이지 3, 전체 10페이지') 형태로 현재/전체 페이지 전달
  • Web: role="navigation" + aria-label="페이지 탐색" + 현재 페이지에 aria-current="page" 적용

터치 타겟#

  • 각 페이지 버튼 최소 크기: 44x44dp

크로스 플랫폼 차이점 (Platform Differences)#

항목FlutterWeb
클래스명PaginationPagination (동일)
페이지 기준1-based1-based
버튼div 기반 정사각 버튼<div role="button"> 정사각 버튼
생략 표시 텍스트 (클릭 시 범위 점프) 텍스트 (클릭 시 범위 점프)
호버MouseRegion + 색 전환CSS :hover 토큰 클래스
  • Table: 페이지네이션이 필요한 대용량 테이블 데이터에 사용
  • Select: 페이지 크기 선택 드롭다운과 조합