Skip to content

Commit 66e222c

Browse files
committed
feat(ui-pagination): add prop to customize screenreader label on buttons
The new prop, called screenReaderLabelPageButton allows to customize screenreader messages on the page buttons (e.g. 1,2,3,4...) INSTUI-4602
1 parent 0d32bd0 commit 66e222c

File tree

6 files changed

+67
-8
lines changed

6 files changed

+67
-8
lines changed

packages/ui-pagination/src/Pagination/PaginationButton/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class PaginationButton extends Component<PaginationPageProps> {
6969
{...props}
7070
aria-current={this.props.current ? 'page' : undefined}
7171
elementRef={this.handleRef}
72+
{...(this.props.screenReaderLabel
73+
? { 'aria-label': this.props.screenReaderLabel }
74+
: {})}
7275
>
7376
{this.props.children}
7477
</BaseButton>

packages/ui-pagination/src/Pagination/PaginationButton/props.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ type PaginationPageOwnProps = {
5050
| React.MouseEvent<HTMLButtonElement>
5151
| React.FocusEvent<HTMLInputElement>
5252
) => void
53+
/**
54+
* The text screenreaders should say when this button is in focus (sets the
55+
* `aria-label` attribute).
56+
* If left undefined (default) SRs will announce text in the child node(s).
57+
*/
58+
screenReaderLabel?: string
5359
}
5460

5561
type PropKeys = keyof PaginationPageOwnProps
@@ -65,13 +71,14 @@ type PaginationPageProps =
6571
const propTypes: PropValidators<PropKeys> = {
6672
children: PropTypes.node.isRequired,
6773
current: PropTypes.bool,
68-
onClick: PropTypes.func
74+
onClick: PropTypes.func,
75+
screenReaderLabel: PropTypes.string
6976
}
7077

7178
const allowedProps: AllowedPropKeys = [
7279
'children',
73-
'current'
74-
80+
'current',
81+
'screenReaderLabel'
7582
// we don't want to pass onClick
7683
// 'onClick'
7784
]

packages/ui-pagination/src/Pagination/README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ The pagination component provides props to handle most of the pagination use-cas
6363
render(<Example />)
6464
```
6565

66-
You can set any `totalPageNumber`, the component can handle it easily. Furthermore, you can set
67-
`siblingCount`, which indicates how many pages are visible on either side of the `currentPage` and the
68-
`boundaryCount`, which indicates how many pages are visible in the beginning and end.
66+
You can set any `totalPageNumber`, the component can handle it easily.\
67+
Furthermore, you can set `siblingCount`, which indicates how many pages are visible on either side of the `currentPage` and the
68+
`boundaryCount`, which indicates how many pages are visible in the beginning and end.\
69+
Also, you can set `screenReaderLabelPageButton` to customize what a screenreader will announce when the button receives focus.
6970

7071
- ```js
7172
class Example extends React.Component {
@@ -87,6 +88,9 @@ You can set any `totalPageNumber`, the component can handle it easily. Furthermo
8788
onPageChange={(nextPage) => this.setState({ currentPage: nextPage })}
8889
siblingCount={3}
8990
boundaryCount={2}
91+
screenReaderLabelPageButton={(currentPage, totalPageNumber) =>
92+
`Page ${currentPage} of ${totalPageNumber}`
93+
}
9094
/>
9195
)
9296
}
@@ -110,6 +114,9 @@ You can set any `totalPageNumber`, the component can handle it easily. Furthermo
110114
onPageChange={(nextPage) => setCurrentPage(nextPage)}
111115
siblingCount={3}
112116
boundaryCount={2}
117+
screenReaderLabelPageButton={(currentPage, totalPageNumber) =>
118+
`Page ${currentPage} of ${totalPageNumber}`
119+
}
113120
/>
114121
)
115122
}
@@ -531,6 +538,7 @@ type: embed
531538
<Guidelines>
532539
<Figure recommendation="a11y" title="Accessibility">
533540
<Figure.Item>Ensure page links and the next/previous buttons are labeled correctly for screen readers</Figure.Item>
541+
<Figure.Item>Use `screenReaderLabelPageButton` or `screenReaderLabelNumberInput` for better screenreader experience</Figure.Item>
534542
</Figure>
535543
</Guidelines>
536544
```

packages/ui-pagination/src/Pagination/__tests__/Pagination.test.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,5 +1128,26 @@ describe('<Pagination />', () => {
11281128
)
11291129
expect(container.firstChild).toHaveTextContent('12345678910Next Page')
11301130
})
1131+
1132+
it('should add aria-label when screenReaderLabelPageButton is set', async () => {
1133+
render(
1134+
<Pagination
1135+
labelNext="Next Page"
1136+
labelPrev="Previous Page"
1137+
totalPageNumber={5}
1138+
screenReaderLabelPageButton={(currentPage, totalPageNumber) =>
1139+
`Page ${currentPage} of ${totalPageNumber}`
1140+
}
1141+
/>
1142+
)
1143+
const paginationButtons = screen.getAllByRole('button', { name: /\d$/ })
1144+
1145+
for (let i: number = 0; i < paginationButtons.length; i++) {
1146+
expect(paginationButtons[i]).toHaveAttribute(
1147+
'aria-label',
1148+
`Page ${i + 1} of ${paginationButtons.length}`
1149+
)
1150+
}
1151+
})
11311152
})
11321153
})

packages/ui-pagination/src/Pagination/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,14 @@ class Pagination extends Component<PaginationProps> {
332332
key={i}
333333
onClick={() => this.handleNavigation(i, currentPage)}
334334
current={i === currentPage}
335+
{...(this.props.screenReaderLabelPageButton
336+
? {
337+
screenReaderLabel: this.props.screenReaderLabelPageButton(
338+
i,
339+
this.props.totalPageNumber!
340+
)
341+
}
342+
: {})}
335343
>
336344
{this.props.renderPageIndicator?.(i, currentPage)}
337345
</Pagination.Page>

packages/ui-pagination/src/Pagination/props.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ type PaginationOwnProps = {
9797
*
9898
* (__only__ for `input` variant)
9999
*/
100-
labelNumberInput?: (numberOfPages: number) => React.ReactNode
100+
labelNumberInput?: (totalPageNumber: number) => React.ReactNode
101101

102102
/**
103103
* ScreenReaderLabel for number input
@@ -106,7 +106,17 @@ type PaginationOwnProps = {
106106
*/
107107
screenReaderLabelNumberInput?: (
108108
currentPage: number,
109-
numberOfPages: number
109+
totalPageNumber: number
110+
) => string
111+
112+
/**
113+
* ScreenReaderLabel for page number buttons
114+
*
115+
* (__only__ for `full` and `compact variants)
116+
*/
117+
screenReaderLabelPageButton?: (
118+
currentPage: number,
119+
totalPageNumber: number
110120
) => string
111121

112122
/**
@@ -212,6 +222,7 @@ const propTypes: PropValidators<PropKeys> = {
212222
labelLast: PropTypes.string,
213223
labelNumberInput: PropTypes.func,
214224
screenReaderLabelNumberInput: PropTypes.func,
225+
screenReaderLabelPageButton: PropTypes.func,
215226
variant: PropTypes.oneOf(['full', 'compact', 'input']),
216227
margin: PropTypes.string,
217228
as: PropTypes.elementType,
@@ -239,6 +250,7 @@ const allowedProps: AllowedPropKeys = [
239250
'labelLast',
240251
'labelNumberInput',
241252
'screenReaderLabelNumberInput',
253+
'screenReaderLabelPageButton',
242254
'variant',
243255
'margin',
244256
'as',

0 commit comments

Comments
 (0)