Live Preview
…
Pagination Component
Skill này hướng dẫn tạo component Pagination — điều hướng giữa các trang dữ liệu cho table, list, và grid.
1. Mục tiêu (Objective)
Tạo component Pagination cho table/list navigation: page numbers, prev/next, per-page selector. Luôn đi cùng Table hoặc data list.
2. AI Context & Intent (Ngữ cảnh cho AI)
Khi nào dùng Pagination?
- Table data: Navigate qua nhiều trang rows
- Search results: Page qua kết quả tìm kiếm
- Product listing: Browse danh sách sản phẩm
- Admin dashboard: List users, orders, logs
⚠️ Phân biệt Pagination vs Infinite Scroll vs Load More (QUAN TRỌNG)
| Tiêu chí | Pagination | Infinite Scroll | Load More |
|---|---|---|---|
| UX | Jump to any page | Auto-load on scroll | Manual "Load More" button |
| Best for | Structured data, known total | Social feed, timeline | Mixed content |
| SEO | ✅ URL per page | ❌ Hard to index | ❌ Hard to index |
| Mobile | ⚠️ Small buttons | ✅ Natural swipe | ✅ Simple |
| Ví dụ | Table, admin list | News feed, Instagram | Comments section |
Decision Tree cho AI
text
Data có nhiều pages?
├─ Structured data + cần random access → Pagination
│ ├─ Table → Pagination (default) + per-page selector
│ ├─ Search results → Pagination (default)
│ ├─ Mobile table → Pagination (simple: prev/next only)
│ └─ Compact header → Pagination (compact: "1 of 10")
│
├─ Feed / timeline / social → Infinite scroll
├─ Comments / replies → Load More button
└─ ≤ 20 items → Show all, no pagination needed
3. Anatomy
text
┌────────────────────────────────────────────────────────────┐
│ ◀ 1 2 [3] 4 5 ... 10 ▶ 10 per page ▼ │
│ ↑ ↑ ↑↑ ↑ ↑ ↑ │
│ │ │ ││ │ │ └─ Per-page selector │
│ │ │ │└─ active │ └─ Next button │
│ │ │ └─ --primary │ │
│ │ └─ page buttons └─ Ellipsis │
│ └─ Prev button │
│ │
│ Showing 21-30 of 100 items │ ← Info text
└────────────────────────────────────────────────────────────┘
4. Platform Mapping
| Platform | Component | Key Difference |
|---|---|---|
| Web | Pagination | Page numbers + prev/next buttons |
| iOS | ❌ (infinite scroll) | iOS không dùng pagination, dùng pull-to-load |
| Android (M3) | ❌ (infinite scroll) | M3 prefer infinite scroll |
| Carbon | Pagination | Full: page numbers + per-page + total count |
Cross-platform note: Pagination là Web/Desktop concept. Mobile platforms prefer infinite scroll.
5. Variants
| Variant | Mô tả |
|---|---|
default |
Full page numbers with prev/next |
simple |
Prev/Next only (no numbers) |
compact |
"1 of 10" text with arrows |
with-select |
Includes per-page selector (10/25/50/100) |
5.4. Slot Map (Figma ↔ Code)
📎 Source:
slot-manifest.json→pagination· Layer: item
| Figma Slot | data-slot |
CSS Class | Required | Accepts |
|---|---|---|---|---|
| Root | pagination |
.pagination |
✅ | — |
| Prev | pagination-prev |
— | ✅ | icon-button |
| Next | pagination-next |
— | ✅ | icon-button |
| Item | pagination-item |
— | ✅ (n×) | page-button |
| Ellipsis | pagination-ellipsis |
— | ❌ | … |
6. Token Mapping
📦 Atomic Mapping: Xem
ATOMIC-MAPPING.md→ mục pagination — Density Tier: comp.Active page dùng
--primary/--primary-foreground, default fg dùng--muted-foreground, hover dùng--state-layer-hover. Component token JSON files đã deprecated.
7. Props & API
typescript
interface PaginationProps {
currentPage: number;
totalPages: number;
variant?: 'default' | 'simple' | 'compact' | 'with-select';
siblingCount?: number;
showFirstLast?: boolean;
perPage?: number;
perPageOptions?: number[];
totalItems?: number;
onChange: (page: number) => void;
onPerPageChange?: (perPage: number) => void;
}
8. Accessibility (a11y)
- Container:
navelement witharia-label="Pagination". - Current page:
aria-current="page". - Disabled prev/next:
aria-disabled="true". - Keyboard:
Tabmoves between buttons,Enter/Spaceactivates.
9. Best Practices & Rules
- Ellipsis: Show
...when too many pages (e.g., 1 2 ... 5 6 7 ... 99 100). - Mobile: Switch to simple variant (prev/next only) on small screens.
- Pair with Table: Always co-locate with table, show total items count.
- Không Hardcode: Mọi giá trị từ Token.
10. Example Usage
jsx
{/* Standard table pagination */}
<Pagination
currentPage={3}
totalPages={10}
totalItems={100}
onChange={handlePageChange}
/>
{/* With per-page selector */}
<Pagination
currentPage={1}
totalPages={20}
variant="with-select"
perPage={10}
perPageOptions={[10, 25, 50, 100]}
totalItems={200}
onChange={handlePageChange}
onPerPageChange={handlePerPageChange}
/>
{/* Mobile simple */}
<Pagination
currentPage={page}
totalPages={total}
variant="simple"
onChange={setPage}
/>