Skip to content

Commit 7ee4baa

Browse files
feat(b-pagination, b-pagination-nav): improve aria accessibility (closes: bootstrap-vue#4811, bootstrap-vue#4160) (bootstrap-vue#4810)
Co-authored-by: Jacob Müller <jacob.mueller.elz@gmail.com>
1 parent 5684905 commit 7ee4baa

File tree

6 files changed

+89
-68
lines changed

6 files changed

+89
-68
lines changed

src/components/form-tags/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Form tags
1+
# Form Tags
22

33
> Lightweight custom tagged input form control, with options for customized interface rendering,
44
> duplicate tag detection and optional tag validation.

src/components/pagination-nav/README.md

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -515,23 +515,14 @@ recommended unless the content of the button textually conveys its purpose.
515515

516516
### Keyboard navigation
517517

518-
`<b-pagination-nav>` supports keyboard navigation out of the box, and follows the
519-
[WAI-ARIA roving tabindex](https://www.w3.org/TR/wai-aria-practices-1.2/#kbd_roving_tabindex)
520-
pattern.
521-
522-
- Tabbing into the pagination component will autofocus the current active page button
523-
- <kbd>LEFT</kbd> (or <kbd>UP</kbd>) and <kbd>RIGHT</kbd> (or <kbd>DOWN</kbd>) arrow keys will focus
524-
the previous and next buttons, respectively, in the page list
525-
- <kbd>ENTER</kbd> or <kbd>SPACE</kbd> keys will select (click) the currently focused page button
526-
- Pressing <kbd>TAB</kbd> will move to the next control or link on the page, while pressing
527-
<kbd>SHIFT</kbd>+<kbd>TAB</kbd> will move to the previous control or link on the page.
518+
`<b-pagination-nav>` supports standard <kbd>TAB</kbd> key navigation.
528519

529520
## See also
530521

531522
Refer to the [Router support](/docs/reference/router-links) reference page for router-link specific
532523
props.
533524

534-
For pagination control of a component (such as `<b-table>`), use the
525+
For pagination control of a component (such as `<b-table>`) or a pagination list, use the
535526
[`<b-pagination>`](/docs/components/pagination) component instead.
536527

537528
<!-- Component reference added automatically from component package.json -->

src/components/pagination-nav/pagination-nav.spec.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ describe('pagination-nav', () => {
3232

3333
// NAV Attributes
3434
expect(wrapper.attributes('aria-hidden')).toBe('false')
35+
expect(wrapper.attributes('aria-label')).toBe('Pagination')
3536

3637
// UL Classes
3738
expect($ul.classes()).toContain('pagination')
@@ -41,9 +42,9 @@ describe('pagination-nav', () => {
4142
expect($ul.classes()).not.toContain('justify-content-center')
4243
expect($ul.classes()).not.toContain('justify-content-end')
4344
// UL Attributes
44-
expect($ul.attributes('role')).toBe('menubar')
45+
expect($ul.attributes('role')).not.toBe('menubar')
4546
expect($ul.attributes('aria-disabled')).toBe('false')
46-
expect($ul.attributes('aria-label')).toBe('Pagination')
47+
expect($ul.attributes('aria-label')).not.toBe('Pagination')
4748

4849
wrapper.destroy()
4950
})
@@ -126,7 +127,7 @@ describe('pagination-nav', () => {
126127
expect($ul.classes()).toContain('b-pagination')
127128

128129
// UL Attributes
129-
expect($ul.attributes('role')).toBe('menubar')
130+
expect($ul.attributes('role')).not.toBe('menubar')
130131
expect($ul.attributes('aria-disabled')).toBe('true')
131132

132133
// LI classes

src/components/pagination/pagination.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ export const BPagination = /*#__PURE__*/ Vue.extend({
132132
return pageNum
133133
},
134134
linkProps() {
135-
// Always '#' for pagination component
136-
return { href: '#' }
135+
// No props, since we render a plain button
136+
return {}
137137
}
138138
}
139139
})

src/components/pagination/pagination.spec.js

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ describe('pagination', () => {
5656
if (index === 2) {
5757
expect(li.classes()).toContain('active')
5858
expect(li.classes()).not.toContain('disabled')
59-
expect(pageLink.is('a')).toBe(true)
59+
expect(pageLink.is('button')).toBe(true)
6060
} else {
6161
expect(li.classes()).not.toContain('active')
6262
expect(li.classes()).toContain('disabled')
@@ -78,14 +78,13 @@ describe('pagination', () => {
7878
expect(last.find('.page-link').text()).toEqual('»')
7979

8080
// Page button attrs
81-
expect(page.find('.page-link').attributes('href')).toEqual('#')
81+
expect(page.find('.page-link').attributes('type')).toEqual('button')
8282
expect(page.find('.page-link').attributes('role')).toEqual('menuitemradio')
8383
expect(page.find('.page-link').attributes('aria-checked')).toEqual('true')
8484
expect(page.find('.page-link').attributes('aria-posinset')).toEqual('1')
8585
expect(page.find('.page-link').attributes('aria-setsize')).toEqual('1')
8686
expect(page.find('.page-link').attributes('tabindex')).toEqual('0')
8787
expect(page.find('.page-link').attributes('aria-label')).toEqual('Go to page 1')
88-
expect(page.find('.page-link').attributes('target')).toEqual('_self')
8988

9089
wrapper.destroy()
9190
})
@@ -133,7 +132,7 @@ describe('pagination', () => {
133132
disabled: false
134133
})
135134

136-
const $links = wrapper.findAll('a.page-link')
135+
const $links = wrapper.findAll('button.page-link')
137136
expect($links.length).toBe(5)
138137
expect($links.at(0).text()).toBe('Page 1')
139138
expect($links.at(1).text()).toBe('Page 2')
@@ -388,16 +387,16 @@ describe('pagination', () => {
388387
})
389388
expect(wrapper.is('ul')).toBe(true)
390389
expect(wrapper.findAll('li').length).toBe(5)
391-
expect(wrapper.findAll('a.page-link').length).toBe(4)
392-
expect(wrapper.findAll('a.page-link').is('[aria-controls="foo"]')).toBe(true)
390+
expect(wrapper.findAll('button.page-link').length).toBe(4)
391+
expect(wrapper.findAll('button.page-link').is('[aria-controls="foo"]')).toBe(true)
393392

394393
wrapper.setProps({
395394
ariaControls: null
396395
})
397396
await waitNT(wrapper.vm)
398397
expect(wrapper.findAll('li').length).toBe(5)
399-
expect(wrapper.findAll('a.page-link').length).toBe(4)
400-
expect(wrapper.findAll('a.page-link').is('[aria-controls]')).toBe(false)
398+
expect(wrapper.findAll('button.page-link').length).toBe(4)
399+
expect(wrapper.findAll('button.page-link').is('[aria-controls]')).toBe(false)
401400

402401
wrapper.destroy()
403402
})
@@ -414,28 +413,28 @@ describe('pagination', () => {
414413
})
415414
expect(wrapper.is('ul')).toBe(true)
416415
expect(wrapper.findAll('li').length).toBe(5)
417-
expect(wrapper.findAll('a').length).toBe(4)
416+
expect(wrapper.findAll('button').length).toBe(4)
418417
expect(
419418
wrapper
420-
.findAll('a')
419+
.findAll('button')
421420
.at(0)
422421
.attributes('aria-label')
423422
).toBe('Go to page 1')
424423
expect(
425424
wrapper
426-
.findAll('a')
425+
.findAll('button')
427426
.at(1)
428427
.attributes('aria-label')
429428
).toBe('Go to page 2')
430429
expect(
431430
wrapper
432-
.findAll('a')
431+
.findAll('button')
433432
.at(2)
434433
.attributes('aria-label')
435434
).toBe('Go to page 3')
436435
expect(
437436
wrapper
438-
.findAll('a')
437+
.findAll('button')
439438
.at(3)
440439
.attributes('aria-label')
441440
).toBe('Go to next page')
@@ -654,7 +653,7 @@ describe('pagination', () => {
654653
wrapper
655654
.findAll('li')
656655
.at(3)
657-
.find('a')
656+
.find('button')
658657
.trigger('click')
659658
await waitNT(wrapper.vm)
660659
expect(wrapper.vm.computedCurrentPage).toBe(2)
@@ -667,7 +666,7 @@ describe('pagination', () => {
667666
wrapper
668667
.findAll('li')
669668
.at(6)
670-
.find('a')
669+
.find('button')
671670
.trigger('keydown.space') // Generates a click event
672671
await waitNT(wrapper.vm)
673672
expect(wrapper.vm.computedCurrentPage).toBe(3)
@@ -678,7 +677,7 @@ describe('pagination', () => {
678677
wrapper
679678
.findAll('li')
680679
.at(1)
681-
.find('a')
680+
.find('button')
682681
.trigger('click')
683682
await waitNT(wrapper.vm)
684683
expect(wrapper.vm.computedCurrentPage).toBe(2)
@@ -1031,7 +1030,7 @@ describe('pagination', () => {
10311030
expect(wrapper.is('ul')).toBe(true)
10321031
await waitNT(wrapper.vm)
10331032
// Grab the button links (2 bookends + 3 pages + 2 bookends)
1034-
const links = wrapper.findAll('a.page-link')
1033+
const links = wrapper.findAll('button.page-link')
10351034
expect(links.length).toBe(7)
10361035

10371036
// Sanity check for getBCR override
@@ -1091,7 +1090,7 @@ describe('pagination', () => {
10911090
await waitNT(wrapper.vm)
10921091
expect(wrapper.is('ul')).toBe(true)
10931092
// Grab the button links (2 bookends + 3 pages + 2 bookends)
1094-
const links = wrapper.findAll('a.page-link')
1093+
const links = wrapper.findAll('button.page-link')
10951094
expect(links.length).toBe(7)
10961095

10971096
// Focus the last button
@@ -1121,14 +1120,14 @@ describe('pagination', () => {
11211120
await waitNT(wrapper.vm)
11221121
expect(wrapper.is('ul')).toBe(true)
11231122
// Grab the button links (2 disabled bookends + 4 pages + (-ellipsis) + 2 bookends)
1124-
links = wrapper.findAll('a.page-link')
1123+
links = wrapper.findAll('button.page-link')
11251124
expect(links.length).toBe(6)
11261125

11271126
// Click on the 4th button (page 4, index 3)
11281127
links.at(3).element.click()
11291128
await waitNT(wrapper.vm)
11301129
// Links re-rendered with first bookends enabled and an ellipsis
1131-
links = wrapper.findAll('a.page-link')
1130+
links = wrapper.findAll('button.page-link')
11321131
// The 4th link should be page 4, and retain focus
11331132
expect(document.activeElement).toEqual(links.at(3).element)
11341133

0 commit comments

Comments
 (0)