Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Cannot tab to previously disabled button in modal #5050

Closed
cunninghamzac opened this issue Dec 11, 2015 · 2 comments
Closed

Cannot tab to previously disabled button in modal #5050

cunninghamzac opened this issue Dec 11, 2015 · 2 comments

Comments

@cunninghamzac
Copy link

If you have a button that is disabled when the modal is opened and then becomes enabled later, you can't tab to the button.

Here's a plunk to reproduce it: http://plnkr.co/edit/8oCzQa3hPSloxnudxoG8?p=preview

  1. Click the Open me! button
  2. Enter a value in the Name field and tab to the Address field
  3. Enter a value in the Address field and try to tab to the OK button

Notice that focus never goes to the OK button.

@wesleycho wesleycho added this to the 1.1 (ARIA Accessibility) milestone Dec 11, 2015
@melaniesaraj
Copy link

This issue is related to / a subset of #5421 ('MODAL: Keyboard focus fail with dynamic content').

The problem again is that focusableElementList, which attempts to track all of the focusable elements in the modal, is only populated once per modal (the first time the tab key is pressed after the modal is opened) and never updated.

$uibModalStack uses this cached list -- or more precisely, its first and last elements -- to trap focus in the modal (modal.js:386). When the user presses tab, $uibModalStack checks whether focus is currently on the last focusable element in the modal, and if it is, moves focus to the first focusable element in the modal, instead of letting it escape to the rest of the DOM. (For shift+tab, which is tabbing backwards, switch "first" and "last".) Otherwise, it lets the event propagate.

So we have a problem in this case because the newly-focusable element (the 'OK' button) is later in the DOM than the element stored as the modal's last focusable element (the 'Cancel' button). Whenever we get to 'Cancel' and press tab, the keydown handler sees that we're on the element stored as the last focusable element in the modal, so it sends focus to the element stored as the first element of the modal (the first input box). Similarly, when you shift+tab from the first input box, focus gets manually sent back to the 'Cancel' button.

We will have this problem with any element in a modal that is not initially focusable (whether it wasn't in the DOM at all or was initially disabled) and comes after the initial last focusable element in the DOM or before the initial first focusable element. (Note that you don't have this problem when we add a focusable element after your 'OK' button: Plunk.) Moreover, the tab trapping will fail entirely if we 'lose' the first or last focusable element (whether it's removed from the DOM or no longer focusable): Plunk.

Workaround:

As a user of the library, you can inject $uibModalStack into your module and use clearFocusListCache() to clear the focusable elements list (causing it to be recalculated next time tab is pressed) as appropriate. In this case, that might be whenever the value of either input box changes. Or, depending on the complexity of your application, you might want to attach a keydown handler that clears that cache every time tab is pressed within the dialog. (Of course, this handler would have to run before uib's.)

Proposed fix:

In #5421, @dsuriano suggests calling clearFocusListCache() to clear the focusable elements list whenever space or enter is pressed. That might cover his use cases, but really, the focusable elements could change on any digest cycle. I think it's probably best to just clear and repopulate focusableElementList whenever tab is pressed. Is that too expensive for people's liking? Maybe there could be a way to skip that step (something in $uibModal's options?) if you're creating a modal where you're sure the first and last tabbable elements won't change.

@wesleycho
Copy link
Contributor

I agree with the proposed fix - otherwise, we may have other strange accessibility issues.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants