Skip to content

Commit 731365b

Browse files
authored
fix(b-tabs): allow space to trigger tab activation when no-key-nav is enabled (fixes bootstrap-vue#4323) (bootstrap-vue#4326)
1 parent c686088 commit 731365b

File tree

3 files changed

+86
-7
lines changed

3 files changed

+86
-7
lines changed

src/components/tabs/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,11 +399,11 @@ focus.
399399
Disable keyboard navigation by setting the prop `no-key-nav`. Behavior will now default to regular
400400
browser navigation with TAB key.
401401

402-
| Keypress | Action |
403-
| ------------------------------- | ------------------------------------------------------ |
404-
| <kbd>TAB</kbd> | Move to the next tab button or control on the page |
405-
| <kbd>SHIFT</kbd>+<kbd>TAB</kbd> | Move to the previous tab button or control on the page |
406-
| <kbd>ENTER</kbd> | Activate current focused button's tab |
402+
| Keypress | Action |
403+
| ------------------------------------ | ------------------------------------------------------ |
404+
| <kbd>TAB</kbd> | Move to the next tab button or control on the page |
405+
| <kbd>SHIFT</kbd>+<kbd>TAB</kbd> | Move to the previous tab button or control on the page |
406+
| <kbd>ENTER</kbd> or <kbd>SPACE</kbd> | Activate current focused button's tab |
407407

408408
## Programmatically activating and deactivating tabs
409409

src/components/tabs/tabs.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,10 @@ const BTabButtonHelper = /*#__PURE__*/ Vue.extend({
7171
if (type === 'click') {
7272
stop()
7373
this.$emit('click', evt)
74-
} else if (type === 'keydown' && !this.noKeyNav && key === KeyCodes.SPACE) {
75-
// In keynav mode, SPACE press will also trigger a click/select
74+
} else if (type === 'keydown' && key === KeyCodes.SPACE) {
75+
// For ARIA tabs the SPACE key will also trigger a click/select
76+
// Even with keyboard navigation disabled, SPACE should "click" the button
77+
// See: https://github.com/bootstrap-vue/bootstrap-vue/issues/4323
7678
stop()
7779
this.$emit('click', evt)
7880
} else if (type === 'keydown' && !this.noKeyNav) {

src/components/tabs/tabs.spec.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,83 @@ describe('tabs', () => {
454454
wrapper.destroy()
455455
})
456456

457+
it('pressing space on tab activates the tab, and tab emits click event', async () => {
458+
const App = Vue.extend({
459+
render(h) {
460+
return h(BTabs, { props: { value: 0, noKeyNav: true } }, [
461+
h(BTab, { props: { title: 'one' } }, 'tab 0'),
462+
h(BTab, { props: { title: 'two' } }, 'tab 1'),
463+
h(BTab, { props: { title: 'three' } }, 'tab 2')
464+
])
465+
}
466+
})
467+
const wrapper = mount(App)
468+
expect(wrapper).toBeDefined()
469+
470+
await waitNT(wrapper.vm)
471+
await waitRAF()
472+
const tabs = wrapper.find(BTabs)
473+
expect(tabs).toBeDefined()
474+
expect(tabs.findAll(BTab).length).toBe(3)
475+
476+
const tab1 = tabs.findAll(BTab).at(0)
477+
const tab2 = tabs.findAll(BTab).at(1)
478+
const tab3 = tabs.findAll(BTab).at(2)
479+
480+
expect(wrapper.findAll('.nav-link')).toBeDefined()
481+
expect(wrapper.findAll('.nav-link').length).toBe(3)
482+
483+
// Expect 1st tab (index 0) to be active
484+
expect(tabs.vm.currentTab).toBe(0)
485+
expect(tab1.vm.localActive).toBe(true)
486+
expect(tab2.vm.localActive).toBe(false)
487+
expect(tab3.vm.localActive).toBe(false)
488+
489+
// Try to set 2nd BTab to be active via space keypress
490+
expect(tab2.emitted('click')).not.toBeDefined()
491+
wrapper
492+
.findAll('.nav-link')
493+
.at(1)
494+
.trigger('keydown.space')
495+
await waitNT(wrapper.vm)
496+
await waitRAF()
497+
expect(tabs.vm.currentTab).toBe(1)
498+
expect(tab1.vm.localActive).toBe(false)
499+
expect(tab2.vm.localActive).toBe(true)
500+
expect(tab3.vm.localActive).toBe(false)
501+
expect(tab2.emitted('click')).toBeDefined()
502+
503+
// Try to set 3rd BTab to be active via space keypress
504+
expect(tab3.emitted('click')).not.toBeDefined()
505+
wrapper
506+
.findAll('.nav-link')
507+
.at(2)
508+
.trigger('keydown.space')
509+
await waitNT(wrapper.vm)
510+
await waitRAF()
511+
expect(tabs.vm.currentTab).toBe(2)
512+
expect(tab1.vm.localActive).toBe(false)
513+
expect(tab2.vm.localActive).toBe(false)
514+
expect(tab3.vm.localActive).toBe(true)
515+
expect(tab3.emitted('click')).toBeDefined()
516+
517+
// Try to set 1st BTab to be active via space keypress
518+
expect(tab1.emitted('click')).not.toBeDefined()
519+
wrapper
520+
.findAll('.nav-link')
521+
.at(0)
522+
.trigger('keydown.space')
523+
await waitNT(wrapper.vm)
524+
await waitRAF()
525+
expect(tabs.vm.currentTab).toBe(0)
526+
expect(tab1.vm.localActive).toBe(true)
527+
expect(tab2.vm.localActive).toBe(false)
528+
expect(tab3.vm.localActive).toBe(false)
529+
expect(tab1.emitted('click')).toBeDefined()
530+
531+
wrapper.destroy()
532+
})
533+
457534
it('key nav works', async () => {
458535
const App = Vue.extend({
459536
render(h) {

0 commit comments

Comments
 (0)