Let\'s say I have a document full of focusable elements, either because they are innately focusable (like ) or because they have
The jQuery UI dialog does this by capturing keydown
events, checking if they are for TAB or not, then manually focusing the correct element.
In the interest of completeness, I'm taking the link to jQuery UI dialog that @Domenic provided and filling in the details.
To implement this in the jQuery fashion requires two things:
Listening for Tab
or Shift+Tab
(on keydown
) for the modal element that should trap focus. This is the only means of moving focus via the keyboard. (If you want to prevent mouse interaction with the rest of the document, that is a separate problem solved by covering it with an element to prevent any mouse events from getting through.)
Finding all tabbable elements inside the modal element. These are a subset of all focusable elements, excluding those that have tabindex="-1"
.
Tab
goes forward. Shift+Tab
goes backwards. Any time Tab
is pressed while the last tabbable element in the modal element is focused, the first should receive focus. Similarly, any time Shift+Tab
is pressed while the first tabbable element is focused, the last should receive focus. This will keep focus inside the modal element.
The hard part is knowing which elements are tabbable. Since tabbable elements are all focusable elements that don't have tabindex="-1"
, then we need to know know which elements are focusable. Since there's no property to determine if an element is focusable, jQuery does it by hard-coding the following cases:
input
, select
, textarea
, button
, and object
elements that aren't disabled.a
and area
elements that have an href
or have a numerical value for tabindex
set.tabindex
set.It's not enough to check for these three cases. jQuery goes on to ensure that the element is visible. This means both of the following must be true:
display: none
.visibility
is visible
. This means that the nearest ancestor to have visibility
set must have a value of visible
. If no ancestor has visibility
set, then the computed value is visible
.It should be noted that jQuery's :visible selector does not look correct for this implementation because it says "elements with visibility: hidden
…are considered to be visible," but they are not focusable.
The jqModal jQuery plugin does this out of the box by setting the modal
option to true. The examples on this page with forms should show it. I remember going through the code to see what was happening and you could do it quite easily with plain JS.