Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lemon-pigs-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

Adds new a11y improvements to Pagination.
28 changes: 20 additions & 8 deletions src/Pagination/model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export function buildPaginationModel(
for (let idx = 0; idx < sorted.length; idx++) {
const num = sorted[idx]
const selected = num === currentPage
const last = sorted[idx - 1]
const next = sorted[idx + 1]
const lastDelta = num - last
const nextDelta = num - next
const preceedsBreak = nextDelta !== -1

if (idx === 0) {
if (num !== 1) {
// If the first page isn't page one,
Expand All @@ -78,15 +84,15 @@ export function buildPaginationModel(
type: 'NUM',
num,
selected,
preceedsBreak,
})
} else {
const last = sorted[idx - 1]
const delta = num - last
if (delta === 1) {
if (lastDelta === 1) {
pages.push({
type: 'NUM',
num,
selected,
preceedsBreak,
})
} else {
// We skipped some, so add a break
Expand All @@ -98,6 +104,7 @@ export function buildPaginationModel(
type: 'NUM',
num,
selected,
preceedsBreak: false,
})
}
}
Expand All @@ -124,6 +131,7 @@ type PageType = {
num: number
disabled?: boolean
selected?: boolean
preceedsBreak?: boolean
}

export function buildComponentData(
Expand Down Expand Up @@ -169,11 +177,15 @@ export function buildComponentData(
case 'NUM': {
key = `page-${page.num}`
content = String(page.num)
if (page.selected) {
Object.assign(props, {as: 'em', 'aria-current': 'page'})
} else {
Object.assign(props, {href: hrefBuilder(page.num), 'aria-label': `Page ${page.num}`, onClick})
}
Object.assign(props, {
href: hrefBuilder(page.num),
// We append "..." to the aria-label for pages that preceed a break because screen readers will
// change the tone the text is read in.
// This is a slightly nicer experience than skipping a bunch of numbers unexpectedly.
'aria-label': `Page ${page.num}${page.preceedsBreak ? '...' : ''}`,
onClick,
'aria-current': page.selected ? 'page' : undefined,
})
break
}
case 'BREAK': {
Expand Down
10 changes: 5 additions & 5 deletions src/__tests__/Pagination/PaginationModel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('Pagination model', () => {
const slice = last(model, 5)

const expected = [
{type: 'NUM'},
{type: 'NUM', preceedsBreak: true},
{type: 'BREAK'},
{type: 'NUM', num: 9},
{type: 'NUM', num: 10},
Expand All @@ -74,11 +74,11 @@ describe('Pagination model', () => {
const model = buildPaginationModel(10, 5, true, 1, 1)
const expected = [
{type: 'PREV', num: 4},
{type: 'NUM', num: 1},
{type: 'NUM', num: 1, preceedsBreak: true},
{type: 'BREAK'},
{type: 'NUM', num: 4},
{type: 'NUM', num: 5, selected: true},
{type: 'NUM', num: 6},
{type: 'NUM', num: 6, preceedsBreak: true},
{type: 'BREAK'},
{type: 'NUM', num: 10},
{type: 'NEXT', num: 6},
Expand All @@ -95,7 +95,7 @@ describe('Pagination model', () => {
{type: 'NUM', num: 3},
// normally with a surround of 1, only 1 and 3 would be shown
// however, since 1 was already shown, we extend to 4
{type: 'NUM', num: 4},
{type: 'NUM', num: 4, preceedsBreak: true},
{type: 'BREAK'},
]
expect(first(model, 6)).toMatchObject(expected)
Expand Down Expand Up @@ -123,7 +123,7 @@ describe('Pagination model', () => {
{type: 'BREAK', num: 1},
{type: 'NUM', num: 4},
{type: 'NUM', num: 5, selected: true},
{type: 'NUM', num: 6},
{type: 'NUM', num: 6, preceedsBreak: true},
{type: 'BREAK', num: 10},
{type: 'NEXT'},
]
Expand Down