Skip to content
Permalink
Browse files

fix(b-tabs): allow space to trigger tab activation when `no-key-nav` …

…is enabled (fixes #4323) (#4326)
  • Loading branch information
tmorehouse committed Oct 30, 2019
1 parent c686088 commit 731365b27f290fd2266709865b51307edd04e54e
Showing with 86 additions and 7 deletions.
  1. +5 −5 src/components/tabs/README.md
  2. +4 −2 src/components/tabs/tabs.js
  3. +77 −0 src/components/tabs/tabs.spec.js
@@ -399,11 +399,11 @@ focus.
Disable keyboard navigation by setting the prop `no-key-nav`. Behavior will now default to regular
browser navigation with TAB key.

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

## Programmatically activating and deactivating tabs

@@ -71,8 +71,10 @@ const BTabButtonHelper = /*#__PURE__*/ Vue.extend({
if (type === 'click') {
stop()
this.$emit('click', evt)
} else if (type === 'keydown' && !this.noKeyNav && key === KeyCodes.SPACE) {
// In keynav mode, SPACE press will also trigger a click/select
} else if (type === 'keydown' && key === KeyCodes.SPACE) {
// For ARIA tabs the SPACE key will also trigger a click/select
// Even with keyboard navigation disabled, SPACE should "click" the button
// See: https://github.com/bootstrap-vue/bootstrap-vue/issues/4323
stop()
this.$emit('click', evt)
} else if (type === 'keydown' && !this.noKeyNav) {
@@ -454,6 +454,83 @@ describe('tabs', () => {
wrapper.destroy()
})

it('pressing space on tab activates the tab, and tab emits click event', async () => {
const App = Vue.extend({
render(h) {
return h(BTabs, { props: { value: 0, noKeyNav: true } }, [
h(BTab, { props: { title: 'one' } }, 'tab 0'),
h(BTab, { props: { title: 'two' } }, 'tab 1'),
h(BTab, { props: { title: 'three' } }, 'tab 2')
])
}
})
const wrapper = mount(App)
expect(wrapper).toBeDefined()

await waitNT(wrapper.vm)
await waitRAF()
const tabs = wrapper.find(BTabs)
expect(tabs).toBeDefined()
expect(tabs.findAll(BTab).length).toBe(3)

const tab1 = tabs.findAll(BTab).at(0)
const tab2 = tabs.findAll(BTab).at(1)
const tab3 = tabs.findAll(BTab).at(2)

expect(wrapper.findAll('.nav-link')).toBeDefined()
expect(wrapper.findAll('.nav-link').length).toBe(3)

// Expect 1st tab (index 0) to be active
expect(tabs.vm.currentTab).toBe(0)
expect(tab1.vm.localActive).toBe(true)
expect(tab2.vm.localActive).toBe(false)
expect(tab3.vm.localActive).toBe(false)

// Try to set 2nd BTab to be active via space keypress
expect(tab2.emitted('click')).not.toBeDefined()
wrapper
.findAll('.nav-link')
.at(1)
.trigger('keydown.space')
await waitNT(wrapper.vm)
await waitRAF()
expect(tabs.vm.currentTab).toBe(1)
expect(tab1.vm.localActive).toBe(false)
expect(tab2.vm.localActive).toBe(true)
expect(tab3.vm.localActive).toBe(false)
expect(tab2.emitted('click')).toBeDefined()

// Try to set 3rd BTab to be active via space keypress
expect(tab3.emitted('click')).not.toBeDefined()
wrapper
.findAll('.nav-link')
.at(2)
.trigger('keydown.space')
await waitNT(wrapper.vm)
await waitRAF()
expect(tabs.vm.currentTab).toBe(2)
expect(tab1.vm.localActive).toBe(false)
expect(tab2.vm.localActive).toBe(false)
expect(tab3.vm.localActive).toBe(true)
expect(tab3.emitted('click')).toBeDefined()

// Try to set 1st BTab to be active via space keypress
expect(tab1.emitted('click')).not.toBeDefined()
wrapper
.findAll('.nav-link')
.at(0)
.trigger('keydown.space')
await waitNT(wrapper.vm)
await waitRAF()
expect(tabs.vm.currentTab).toBe(0)
expect(tab1.vm.localActive).toBe(true)
expect(tab2.vm.localActive).toBe(false)
expect(tab3.vm.localActive).toBe(false)
expect(tab1.emitted('click')).toBeDefined()

wrapper.destroy()
})

it('key nav works', async () => {
const App = Vue.extend({
render(h) {

0 comments on commit 731365b

Please sign in to comment.
You can’t perform that action at this time.