Component Contract
Pagination
Navigation control for multi-page content, enabling CAAT Pension Plan members to move between pages of results, tables, and listings across the member experience.
Live Demo
Basic Pagination
Rendered
With Icons (Chevron Arrows)
Rendered
Sizing (Small, Default, Large)
Rendered
Small
Default
Large
With Results Text
Rendered
States
Follows the Interaction States matrix. Page links implement default, hover, focus, active (current page), and disabled (boundary). The static is-* classes mirror the live pseudo-class states.
Rendered
Code sample
HTML
<!-- Basic pagination -->
<nav aria-label="Page navigation">
<ul class="caat-pagination">
<li class="caat-pagination__item caat-pagination__item--disabled">
<a class="caat-pagination__link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
</li>
<li class="caat-pagination__item caat-pagination__item--active">
<a class="caat-pagination__link" href="#" aria-current="page">1</a>
</li>
<li class="caat-pagination__item">
<a class="caat-pagination__link" href="#">2</a>
</li>
<li class="caat-pagination__item">
<a class="caat-pagination__link" href="#">Next</a>
</li>
</ul>
</nav>
<!-- With chevron icons -->
<nav aria-label="Page navigation">
<ul class="caat-pagination">
<li class="caat-pagination__item">
<a class="caat-pagination__link" href="#" aria-label="Previous page">
<i class="bi bi-chevron-left" aria-hidden="true"></i>
</a>
</li>
<li class="caat-pagination__item caat-pagination__item--active">
<a class="caat-pagination__link" href="#" aria-current="page">1</a>
</li>
<li class="caat-pagination__item">
<a class="caat-pagination__link" href="#" aria-label="Next page">
<i class="bi bi-chevron-right" aria-hidden="true"></i>
</a>
</li>
</ul>
</nav>
<!-- With results text -->
<div class="caat-pagination-wrapper">
<span class="caat-pagination__results">Showing 1–10 of 97 results</span>
<nav aria-label="Page navigation">
<ul class="caat-pagination">…</ul>
</nav>
</div>
1. Summary
| Component name | caat/components/pagination |
| Purpose | Navigation control for splitting long content across multiple pages. Used in member dashboards, contribution history tables, search results, and document listings to provide clear, accessible page navigation. |
| Status | New Planned |
| Variants | Basic (text labels), Icon (chevron arrows), Small, Default, Large |
| Options | Results summary text, ellipsis for truncated ranges, disabled state for first/last boundaries |
| AEM resource type | caat/components/pagination |
| AEM category | CAAT Components – Navigation |
2. Design Tokens
| Token | Role | Default Value |
|---|---|---|
--caat-blue-900 | Active page background & primary text colour | #003750 |
--caat-blue-700 | Hover border colour | #0b5a80 |
--caat-blue-100 | Hover background | #e7f4fb |
--caat-green | Available for success/confirmation states | #55a546 |
--caat-grey-200 | Default border & disabled text colour | #dfe6ef |
--caat-focus | Focus ring outline colour | #4d90fe |
--caat-ink | Results text & ellipsis colour | #102637 |
--caat-radius | Border radius for pagination links | .75rem |
--caat-font-primary | Font family | 'Libre Franklin', sans-serif |
3. Authoring Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| Total Items | Number | Yes | Total number of items to paginate. Drives page count calculation. |
| Items Per Page | Number (dropdown: 10, 20, 50) | Yes | Number of items displayed per page. Default: 10. |
| Current Page | Number | Yes | The currently active page (1-based). Default: 1. |
| Navigation Style | Dropdown (text | icon) | No | Default: text. "text" renders "Previous/Next" labels; "icon" renders chevron arrows. |
| Size | Dropdown (sm | default | lg) | No | Default: default. Controls touch-target sizing. |
| Show Results Text | Toggle (boolean) | No | Default: off. When enabled, shows "Showing X–Y of Z results" text. |
| Aria Label | Text field | No | Custom aria-label for the <nav> element. Default: "Page navigation". |
4. Validation Rules
- Total Items must be a positive integer greater than 0.
- Items Per Page must be a positive integer; component will not render if set to 0.
- Current Page must be between 1 and the calculated total page count.
- Previous link is disabled when Current Page is 1; Next link is disabled when Current Page equals total page count.
- If total pages ≤ 1, the pagination component should not render (nothing to paginate).
- When total pages exceed 7, middle pages are truncated with an ellipsis ("…").
5. Content Guidance
| Guideline | Detail |
|---|---|
| Use for | Contribution history tables, search results, document listings, member notifications — any content that spans multiple pages. |
| Placement | Below the content being paginated, centred or right-aligned. Optionally include results summary text on the left. |
| Text labels | "Previous" and "Next" are the default labels. Keep labels short and translatable. |
| Icon variant | Preferred when space is limited (e.g., mobile layouts or dense data tables). Always include aria-label on icon-only links. |
| Results text | Format: "Showing X–Y of Z results". Use en-dash (–) not hyphen. Helps members orient themselves within large result sets. |
| Don't | Don't use pagination for fewer than two pages. Don't use for content that benefits from infinite scroll (e.g., news feeds). Don't mix text and icon styles within the same pagination instance. |
6. Semantic HTML
HTL / Markup contract
<!-- Basic pagination -->
<nav aria-label="Page navigation">
<ul class="caat-pagination">
<li class="caat-pagination__item caat-pagination__item--disabled">
<a class="caat-pagination__link" href="#" tabindex="-1"
aria-disabled="true">Previous</a>
</li>
<li class="caat-pagination__item caat-pagination__item--active">
<a class="caat-pagination__link" href="#"
aria-current="page">1</a>
</li>
<li class="caat-pagination__item">
<a class="caat-pagination__link" href="#">2</a>
</li>
<li class="caat-pagination__item">
<a class="caat-pagination__link" href="#">Next</a>
</li>
</ul>
</nav>
<!-- With results text wrapper -->
<div class="caat-pagination-wrapper">
<span class="caat-pagination__results">
Showing 1–10 of 97 results
</span>
<nav aria-label="Page navigation">
<ul class="caat-pagination">…</ul>
</nav>
</div>
Key decisions
<nav>wraps the pagination with a descriptivearia-labelfor landmark navigation.<ul>/<li>provides a list structure so screen readers announce the item count.aria-current="page"on the active link tells assistive technology which page is selected.aria-disabled="true"andtabindex="-1"on disabled Previous/Next links remove them from the tab order.- Icon-only links (
bi-chevron-left/bi-chevron-right) requirearia-label="Previous page"/aria-label="Next page". - Ellipsis uses
aria-hidden="true"to avoid confusing screen reader output.
7. CSS Contract
| Selector | Purpose |
|---|---|
.caat-pagination | Base container — flexbox list reset, gap, font-family. |
.caat-pagination__item | List item wrapper. |
.caat-pagination__link | Clickable page link — min 44×44 touch target, border, border-radius, transitions. |
.caat-pagination__item--active .caat-pagination__link | Active page — blue-900 background, white text, pointer-events none. |
.caat-pagination__item--disabled .caat-pagination__link | Disabled state — greyed out, reduced opacity, pointer-events none. |
.caat-pagination--sm | Small size modifier — reduced min-width/height and font-size. |
.caat-pagination--lg | Large size modifier — increased min-width/height and font-size. |
.caat-pagination__ellipsis | Non-interactive ellipsis indicator for truncated page ranges. |
.caat-pagination__results | Results summary text (e.g., "Showing 1–10 of 97 results"). |
.caat-pagination-wrapper | Flex wrapper for results text + centred pagination layout. |
Sample CSS
.caat-pagination {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.25rem;
padding: 0;
margin: 0;
list-style: none;
font-family: var(--caat-font-primary, 'Libre Franklin', sans-serif);
}
.caat-pagination__link {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
padding: 0.375rem 0.75rem;
color: var(--caat-blue-900, #003366);
background-color: #fff;
border: 1px solid var(--caat-grey-200, #e9ecef);
border-radius: var(--caat-radius, 0.375rem);
text-decoration: none;
transition: background-color 0.15s, border-color 0.15s;
}
.caat-pagination__link:hover {
background-color: var(--caat-blue-100, #cfe2ff);
border-color: var(--caat-blue-700, #004a99);
}
.caat-pagination__link:focus-visible {
outline: 3px solid var(--caat-focus, #4d90fe);
outline-offset: 2px;
}
.caat-pagination__item--active .caat-pagination__link {
background-color: var(--caat-blue-900, #003366);
border-color: var(--caat-blue-900, #003366);
color: #fff;
pointer-events: none;
}
.caat-pagination__item--disabled .caat-pagination__link {
color: var(--caat-grey-200, #e9ecef);
background-color: #f8f9fa;
pointer-events: none;
opacity: 0.65;
}
8. Accessibility
| Requirement | Implementation |
|---|---|
| Landmark | Wrap in <nav> with a descriptive aria-label (e.g., "Page navigation" or "Search results pagination"). |
| Current page | Active page link uses aria-current="page" so screen readers announce "current page". |
| Disabled links | Use aria-disabled="true" and tabindex="-1" to remove from tab order. CSS sets pointer-events: none. |
| Icon-only links | Chevron-only Previous/Next links must include aria-label="Previous page" / aria-label="Next page". |
| Touch targets | Minimum 44×44px touch target on all interactive elements (WCAG 2.5.8 Target Size). |
| Colour contrast | Active page (white on blue-900) meets WCAG 2.1 AA 4.5:1. Hover state meets 3:1 non-text contrast. |
| Focus visible | 3px solid focus ring using --caat-focus token with 2px offset. Visible on all interactive links. |
| Keyboard | All page links reachable via Tab. Enter/Space activates the link. Disabled links are skipped. |
| Reduced motion | Hover/focus transitions respect prefers-reduced-motion: reduce. |
9. SEO
- Use
rel="prev"andrel="next"on Previous/Next<a>links to signal paginated series to search engines. - Each page's URL should have a distinct, crawlable
href(e.g.,?page=2) — avoid JavaScript-only navigation. - Pagination links are server-side rendered as standard
<a>elements, ensuring crawlability. - Include a canonical URL on each paginated page to prevent duplicate content issues.
- The
<nav>landmark allows bots to identify the pagination region and skip to main content.
10. Analytics
Analytics are captured through the shared data-analytics-component attribute on the component root (emitted automatically) and reported to the central data layer. Event names and payloads follow the organisation's standard analytics schema — defined centrally with the analytics team, not invented per component — so no bespoke tracking is specified here.
11. AEM Notes
- Resource type:
caat/components/pagination - Component group: CAAT Components – Navigation
- Proxy: Create as a proxy component under
/apps/caat/components/pagination. - Policies: Configure default items per page and size variant per template via content policies.
- Sling Model:
com.caat.core.models.PaginationModel— exposestotalItems,itemsPerPage,currentPage,totalPages,pages[],hasPrevious,hasNext,showResults. - HTL:
pagination.html— usesdata-sly-listto iterate page items,data-sly-attributefor active/disabled states. - Client library:
caat.components.pagination(categories:caat.site). - Integration: Typically consumed by list/search components rather than placed independently. The parent component passes total count and current page to the pagination model.
12. Dialog Model (YAML)
Simplified model — shows field intent and Granite UI resource types, not the literal cq:dialog node tree (e.g. select options are authored as child items nodes).
title: Pagination
description: Multi-page navigation for lists, tables, and search results.
fields:
- name: totalItems
label: Total Items
type: numberfield
required: true
min: 1
helpText: Total number of items to paginate.
- name: itemsPerPage
label: Items Per Page
type: select
required: true
options:
- value: 10
label: "10"
- value: 20
label: "20"
- value: 50
label: "50"
defaultValue: 10
helpText: Number of items shown per page.
- name: navStyle
label: Navigation Style
type: select
required: false
options:
- value: text
label: Text (Previous / Next)
- value: icon
label: Icon (Chevron arrows)
defaultValue: text
helpText: Controls whether Previous/Next use text labels or chevron icons.
- name: size
label: Size
type: select
required: false
options:
- value: sm
label: Small
- value: default
label: Default
- value: lg
label: Large
defaultValue: default
helpText: Controls the pagination touch-target and font size.
- name: showResults
label: Show Results Summary
type: checkbox
required: false
defaultValue: false
helpText: Displays "Showing X–Y of Z results" alongside the pagination.
- name: ariaLabel
label: Aria Label
type: textfield
required: false
maxLength: 80
defaultValue: Page navigation
helpText: Custom aria-label for the nav element. Important for pages with multiple pagination instances.
13. QA Acceptance Checklist
- Basic pagination renders Previous, page numbers 1–5, and Next correctly.
- Previous link is disabled on page 1; Next link is disabled on the last page.
- Active page shows blue-900 background with white text and
aria-current="page". - Icon variant renders chevron-left and chevron-right with appropriate
aria-label. - Small, Default, and Large sizes render with correct min-width/min-height touch targets.
- Results text ("Showing X–Y of Z results") displays correctly when enabled.
- Ellipsis renders for truncated page ranges (total pages > 7) with
aria-hidden="true". - Focus ring (3px solid, --caat-focus) is visible on all interactive links.
- Keyboard navigation: Tab reaches all enabled links; disabled links are skipped.
- Hover state applies blue-100 background on non-active, non-disabled links.
- Pagination does not render when total pages ≤ 1.
- Responsive: pagination centres and simplifies at mobile breakpoint (< 576px).
- Analytics events (
pagination-click,pagination-view) fire with correct data attributes. - Cross-browser tested: Chrome, Firefox, Safari, Edge.
14. Definition of Done
| Area | Done means |
|---|---|
| Design | Figma component matches this contract. All size variants (sm, default, lg) documented. Icon and text navigation styles provided. Results summary layout included. Responsive behaviour defined. |
| Development | AEM proxy component created. HTL template emits semantic HTML per Section 6. CSS uses design tokens exclusively. All states (active, disabled, hover, focus) implemented. Touch targets meet 44px minimum. Unit tests pass. |
| QA | All items in the QA Acceptance Checklist (Section 13) pass. Manual accessibility audit completed. Screen-reader testing (NVDA, VoiceOver) confirms aria-current and disabled state announcements. Cross-browser tested. |
| Launch | Component deployed to AEM production. Integrated with list/search parent components. Content authors trained. Documentation published. Analytics dashboards confirmed receiving events. |