Skip to content

Commit

Permalink
Cycle focus between the body and page tab sequence
Browse files Browse the repository at this point in the history
See testing-library#365 for context
  • Loading branch information
juanca committed Jun 19, 2020
1 parent f4eae9c commit efa87a3
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 6 deletions.
29 changes: 27 additions & 2 deletions src/__tests__/tab.js
Expand Up @@ -111,7 +111,11 @@ test('should cycle elements in document tab order', () => {

userEvent.tab()

// cycle goes back to first element
// cycle goes back to the body
expect(document.body).toHaveFocus()

userEvent.tab()

expect(checkbox).toHaveFocus()
})

Expand All @@ -127,14 +131,27 @@ test('should go backwards when shift = true', () => {
'[data-testid="element"]',
)

radio.focus()
expect(document.body).toHaveFocus()

userEvent.tab({shift: true})

expect(number).toHaveFocus()

userEvent.tab({shift: true})

expect(radio).toHaveFocus()

userEvent.tab({shift: true})

expect(checkbox).toHaveFocus()

userEvent.tab({shift: true})

// cycle goes back to the body
expect(document.body).toHaveFocus()

userEvent.tab({shift: true})

expect(number).toHaveFocus()
})

Expand Down Expand Up @@ -164,6 +181,10 @@ test('should respect tabindex, regardless of dom position', () => {

userEvent.tab()

expect(document.body).toHaveFocus()

userEvent.tab()

expect(radio).toHaveFocus()
})

Expand Down Expand Up @@ -193,6 +214,10 @@ test('should respect tab index order, then DOM order', () => {

userEvent.tab()

expect(document.body).toHaveFocus()

userEvent.tab()

expect(checkbox).toHaveFocus()
})

Expand Down
21 changes: 17 additions & 4 deletions src/tab.js
Expand Up @@ -3,6 +3,22 @@ import {getActiveElement, FOCUSABLE_SELECTOR} from './utils'
import {focus} from './focus'
import {blur} from './blur'

function getNextElement(currentIndex, shift, elements, focusTrap) {
if (focusTrap === document && currentIndex === 0 && shift) {
return document.body
} else if (
focusTrap === document &&
currentIndex === elements.length - 1 &&
!shift
) {
return document.body
} else {
const nextIndex = shift ? currentIndex - 1 : currentIndex + 1
const defaultIndex = shift ? elements.length - 1 : 0
return elements[nextIndex] || elements[defaultIndex]
}
}

function tab({shift = false, focusTrap} = {}) {
const previousElement = getActiveElement(focusTrap?.ownerDocument ?? document)

Expand Down Expand Up @@ -57,10 +73,7 @@ function tab({shift = false, focusTrap} = {}) {
el => el === el.ownerDocument.activeElement,
)

const nextIndex = shift ? index - 1 : index + 1
const defaultIndex = shift ? prunedElements.length - 1 : 0

const nextElement = prunedElements[nextIndex] || prunedElements[defaultIndex]
const nextElement = getNextElement(index, shift, prunedElements, focusTrap)

const shiftKeyInit = {
key: 'Shift',
Expand Down

0 comments on commit efa87a3

Please sign in to comment.