Let's say I have a document full of focusable elements, either because they are innately focusable (like <input type="text">) or because they have tabindex="0" or the like.
Now let's say there's a section of my document that I want to display as a modal dialog box, and I don't want the user to be distracted by anything outside the dialog box. I would like for the tab key to cycle only through focusable elements inside the container element for the dialog box. What is the simplest way to do this?
If possible, I am looking for a solution that doesn't care what the contents of the dialog or the rest of the page are and doesn't try to modify them. That is, I don't want to make the elements outside of the dialog not focusable, for example. First, this requires making a reversible change and keeping track of state. Second, this requires knowing all the possible ways an element could be made focusable. This feels messy, fragile, and unscalable to me.
My first attempt looks like this, but works only in the forward direction (pressing Tab). It doesn't work in the reverse direction (pressing Shift+Tab).
<div>Focusable stuff outside the dialog.</div>
<div class="dialog" tabindex="0">
<!-- Focus should be trapped inside this dialog while it's open -->
<div class="content">
Form contents and focusable stuff here.
</div>
<div class="last-focus" tabindex="0" onfocus="this.parentNode.focus()"></div>
</div>
<div>More focusable stuff outside the dialog.</div>
I'd rather see pure JavaScript solutions. If there is a means of doing this with a library such as jQuery, I would prefer a link to the library code that does this.
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.
any element that has a numerical value for 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:
None of its ancestors are display: none.
The computed value of 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 jQuery UI dialog does this by capturing keydown events, checking if they are for TAB or not, then manually focusing the correct element.
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.
Related
I am building a modal plugin and I would like to be able to set focus to the address bar.
I'd like to be able to do this because I need to be able to restrict tabbing to objects inside of the modal window, but keyboard users and accessibility users should be able to tab out of the modal window to the address bar when they have reached the final element (so that they are not stuck inside the modal). I'm aware that I can do this by setting all of the tabbable elements outside of the modal to have a tabindex of -1, but I'd like to avoid that solution if possible.
I'm aware that it may not be possible to directly set focus to the address bar due to security restrictions. Is there, however, a way to either do this, or defocus the page so that the next element is the address bar?
Having a modal element does not remove the other elements from the visual buffer. A screenreader may read automatically any other element after your modal. So removing the tabindex of elements which might be announced is indeed not a solution.
You may try to remove the focus from any other element using some code like $(".outside_modal").onfocus() {$("#modal-first-link").focus()} but you will have incoherence between your visual focus which will read link targets and the action provided by the keyboard focus.
The only viable solution is to set the modal element in the last position of your DOM.
I'm making a code in javascript right now its really beyond simple but I honestly know nothing about javascript i've been learning for maybe 4 days. so basically I just need a while loop that presses tab every time it loops.
Focus Next Element In Tab Index provides code for advancing focus to the next tabIndexed element.
Or if you're not using tabindex, then it would simply be the next focusable area
Exactly which elements qualify to be focusable areas appears to be platform dependent although there is a recommended list:
Modulo platform conventions, it is suggested that for the following
elements, the tabindex focus flag be set:
a elements that have an href attribute
link elements that have an href attribute
button elements
input elements whose type attribute are not in the Hidden state
select elements
textarea elements
menuitem elements
Elements with a draggable attribute set, if that would enable the user agent to allow the user to begin a drag operations for those elements without the use of a pointing device
Editing hosts
Browsing context containers
Sorting interface th elements
Here's some good general information regarding focus: https://html.spec.whatwg.org/multipage/interaction.html#focus
Sometimes it's needed to make non focusable elements focusable to screenreaders.
An example: when creating jump links like Skip to content that jump to an ID, it's important that the specific element also gets the focus, so not only the viewport is scrolled to the element, but also the focus is set there. Otherwise, a keyboard only user will "jump" back to the beginning of the document as soon as he tries to tab to the next element (expecting the tabbing would begin from the #target object).
Here tabindex="0" is needed, which works as expected. The not so nice thing is that, in other use cases (e.g. when tabbing through the whole page), this is annoying (you usually don't want to focus non focusable elements).
Sort of a workaround could be: create a javascript which, on page load...
scans the entire document for links that are targeting an ID
adds a call to a function addVolatileTabindex to each of those links on activation
when the link is activated, addVolatileTabindex adds a tabindex="0" to the targeted element, then focuses it
it also adds a call to removeVolatileTabindex when the focus is lost from the targeted element
when removeVolatileTabindex is called, the tabindex="0" is removed again
This way, tabindex="0" is only there when it's really needed, and otherwise it's not.
Is there maybe already an existing solution for this? Or are there other ways to achieve this?
Use tabindex="-1" also, you can remove the tabindex once the user tabs off (on blur) that way the focus will never go to the element - even if a user clicks it.
(This scenario is applicable to touch devices, but for the solution it doesn't really matter)
There is a page with a input element and a dropdown list. Depending on what user types, the dropdown element is populated.
When user touches any of the elements on the page except of a dropdown list, the input element should loose the focus.
To do so there is a global event watcher to blur an active element when user touches some other object on a page.
At the moment I am looking for a generic way to specifying cases when the active element should not be blurred (touching the dropdown list should not blur the input).
My idea was to give some tags/attributes to the elements to identify that they are in the same 'family group' and that clicking on one of the children of the group while another is active should not trigger blur event.
However, as those elements can contain children and user clicks on the children, I need to tag every single element or go through the DOM hierarchy to find a parent, which is a dirty solution.
Any suggestions how this can be handled?
I am using Anguarjs.
Thanks a lot!
I have some questions about focus in general (adhering to WC3 format, screw IE). I'm having problems with unintended actions occurring on a widget i am building (using the Dojo Toolkit), and i believe a better general understanding of focus will allow me to solve my problem myself, so here goes:
First of all, which common HTML element are and AREN'T focusable? I've been trying to throw focus around and it works sometimes, and doesnt work other times...
What is the 'highest' level focusable on a page? For instance, can i focus the window? The <body> tag? Specific to dojo, can you focus an entire widget? If the template is widgeted can you focus just highest level of the template (usually a <div>)?
Can focus be 'removed'? Can i remove focus from all elements/objects on the page until the next object is focused? Can i prevent a element from being focusable (like a button)?
What are all the methods through which i can affect focus? Besides calling the focus() method on elements, can focus be set through HTML attributes or in a CSS?
Thanks in advance for what i hope to be some great answers!
Disabled controls can't receive focus according to the HTML4.01 spec
Firefocus, an extension that works over Firebug, could be a great enhancement if you're asking this sort of questions :) Install, restart and look at the Console
Related to focus is the order in which elements are given the focus, that is the order of tabbing navigation and the tabindex attribute with its values -1, 0 or positive when it exists
Any DOM element can receive focus amongst other some event handlers.
See answer 1.
Focus is passed around and not removed.
Focus can only be set by the DOM using JavaScript.
You can also use dojo.place to put things in the correct for focus.