Is there any way in HTML to tell the browser not to allow tab indexing on particular elements?
On my page though there is a sideshow which is rendered with jQuery, when you tab through that, you get a lot of tab presses before the tab control moves to the next visible link on the page as all the things being tabbed through are hidden to the user visually.
You can use tabindex="-1".
Only do this if you are certain it does not remove functionality for keyboard users.
The W3C HTML5 specification supports negative tabindex values:
If the value is a negative integer
The user agent must set the element's tabindex focus flag, but should not allow the element to be reached using sequential focus navigation.
Watch out though that this is a HTML5 feature and might not work with old browsers.
To be W3C HTML 4.01 standard (from 1999) compliant, tabindex would need to be positive.
Sample usage below in pure HTML.
Focusable
<a tabindex="-1" href="#" onclick="return false">Not focusable</a>
Focusable
Don't forget that, even though tabindex is all lowercase in the specs and in the HTML, in Javascript/the DOM that property is called tabIndex.
Don't lose your mind trying to figure out why your programmatically altered tab indices calling element.tabindex = -1 isn't working. Use element.tabIndex = -1.
If these are elements naturally in the tab order like buttons and anchors, removing them from the tab order with tabindex="-1" is kind of an accessibility smell. If they're providing duplicate functionality removing them from the tab order is ok, and consider adding aria-hidden="true" to these elements so assistive technologies will ignore them.
If you are working in a browser that doesn't support tabindex="-1", you may be able to get away with just giving the things that need to be skipped a really high tab index. For example tabindex="500" basically moves the object's tab order to the end of the page.
I did this for a long data entry form with a button thrown in the middle of it. It's not a button people click very often so I didn't want them to accidentally tab to it and press enter. disabled wouldn't work because it's a button.
The way to do this is by adding tabindex="-1". By adding this to a specific element, it becomes unreachable by the keyboard navigation. There is a great article here that will help you further understand tabindex.
Just add the attribute disabled to the element (or use jQuery to do it for you). Disabled prevents the input from being focused or selected at all.
Related
I'm trying to add accessibility to my website, but I'm running into a weird issue with Firefox's accessibility scanner. I've put onclick and onkeydown handlers on my interactive elements, but onkeydown doesn't seem to be enough; Firefox is telling me "Focusable elements should have interactive semantics." The [Learn More] link provided in the notice sends me to this page, which recommends a keydown or keyup event handler... which is already in the code. What am I missing here?
Here's a sample code I used to test the issue:
<img
src="https://www.google.com/logos/doodles/2022/seasonal-holidays-2022-6753651837109831.8-ladc.gif"
alt="Google"
title="Google"
tabindex="0"
onclick="alert('Google')"
onkeydown="alert('Google')">
In Firefox 108's Developer Console, under the Accessibility tab, using "Check for issues" for all issues gives me a notice on this element, saying "Focusable elements should have interactive semantics." despite the fact that onkeydown is defined and performs the same action as onclick.
EDIT: This question is not a duplicate of What does "Focusable Elements Should Have Interactive Semantics" mean in a figure? because that question regards an incorrect use of the role and aria-label attributes in a link, whereas my problem (as explained by the answer I've marked as correct, thank you!) was completely missing the role attribute and better resolved by wrapping this in a button.
The key thing here in the error statement:
Focusable elements should have interactive semantics.
is the word "semantics".
semantics refers to what an element actually "means" or "does" in the context of the page. Specifically, we are talking about the role of an element as exposed to the operating system's underlying accessibility API. An img element (providing it as alt text as you have correctly given it) has default role img (which is obvious, I hope - that comes from the table on this page), which you can view in the ARIA specification. I won't quote anything from that as what's most important in this context is what's not there. Basically, an image is not expected to be interactive - unlike elements with different roles such as button.
If you were to actually test your page with a screenreader - something I would highly recommend every front end developer does with some regularity - you would see the problem. Yes, knowing how your application behaves, you can press a key and have the intended functionality happen. But there's nothing in your HTML that implies that anything interactive will happen here - it's just an image, they're not expected to be interactive. So a screenreader will not announce anything to the effect of "oh by the way you can click on this" (or press enter or whatever) (actually from memory NVDA says "clickable" for elements with click handlers - but other screenreaders such as Voiceover won't, so you shouldn't rely on this. Even knowing the element is "clickable", users without a mouse or who are unable to see where they're clicking will not know how to trigger this "click".).
The solution is to give your element the correct semantics. Since this does something when you click it, and that thing isn't navigation to a new page, it strikes me that the correct role would be button. So you could do this, adding the correct role attribute:
<img
src="https://www.google.com/logos/doodles/2022/seasonal-holidays-2022-6753651837109831.8-ladc.gif"
alt="Google"
title="Google"
tabindex="0"
onclick="alert('Google')"
onkeydown="alert('Google')"
role="button">
This would be a big improvement - I'd expect it to no longer bring up the error you're seeing, as well as to be much more usable to users with assistive technologies.
But, whenever you find yourself using a role which corresponds to an alternative HTML element - and in this case it will not surprise you to know that the button role is automatically applied to the HTML <button> element - you should ask yourself if there's any good reason why you can't just use the correct element.
Only you can answer that question, but I'd be very surprised if such a reason existed. At worst, using a <button> may change your styles, but I'm assuming you have control of the CSS so you can update that as needed.
You do still want the image there because that's seen by sighted users so screenreader users should be told about it the same. What I would do is wrap the image in a button, attach the onclick handler to that button, and remove both the tabindex and the onkeydown, because one of the nice things about using the correct HTML element is that browsers handle most of the behaviour for you, in this case making buttons be in the tab order and trigger their click effect whenever Enter or Space is pressed when focused.
So this would be in my opinion the best way to code this:
<button onclick="alert('Google')">
<img
src="https://www.google.com/logos/doodles/2022/seasonal-holidays-2022-6753651837109831.8-ladc.gif"
alt="Google"
title="Google"
>
<button>
and you should get everything you need, including being accessible "for free" (and the button having the image's alt text as its "accessible name"), and at worst just have to add/update some styles.
Right now my autofocus is on an input that doesn't provide much information for a screenreader... the screenreader would be much better for the visually impaired if it automatically read out the h1 tag on my page. I tried adding an autofocus attribute to my h1 but it didn't do anything. Do I have to do it with javascript?
If you really want to do that (I have the same case as you in a modal) you can add a
tabindex="-1" with your auto focus like that
<h1 mat-dialog-title tabindex="-1" autofocus>Modal name</h1>
The tabindex attribute explicitly defines the navigation order for focusable elements (typically links and form controls) within a page. It can also be used to define whether elements should be focusable or not.
[Both] tabindex="0" and tabindex="-1" have special meaning and provide distinct functionality in HTML. A value of 0 indicates that the element should be placed in the default navigation order. This allows elements that are not natively focusable (such as , , and you understand now ) to receive keyboard focus. Of course one should generally use links and form controls for all interactive elements, but this does allow other elements to be focusable and trigger interaction.
A tabindex="-1" value removes the element from the default navigation flow (i.e., a user cannot tab to it), but it allows it to receive programmatic focus, meaning focus can be set to it from a link or with scripting or autofocus. This can be very useful for elements that should not be tabbed to, but that may need to have focus set to them. like in your case :)
More info: http://webaim.org/techniques/keyboard/tabindex
I recently ran into a similar situation, the Adrien Delabie's answer is partially correct but as it notes you have the problem that this removes the h1 from the navigation flow of the document.
That's bad.
Furthermore while giving something a tabindex makes it focusable VoiceOver (at the time of this writing) ignores non natively focusable elements when focused programmatically.
So I make an element like this
<h1>{{normalHeader}} <a id="specialfocusable" tabindex="-1">{{focusText}}</a> </h1>
Obviously when we decide to focus we focus on the #specialfocusable a element, but first we set the normalHeader to be an empty string and focusText to be the text we want the screen reader to read.
Voiceover reads it, the h1 is still in normal document flow so you can normally tab to it. (I have not had the chance to check in other screenreaders but I believe it shall work, at worst I need to handle a lose focus on the #specialfocusable and set normalHeader back and set focusText to empty string again), the a element is not read unless focus set on it with the focusText.
Of course you should also style the a so it does not look like an a, the same thing would work for any focusable element. Just an a element is the easiest to style.
All else being equal, an h1 can't be focused at all. It doesn't make sense to focus it anyway: It isn't an interactive element. You don't expect clicking on a heading to do anything (as you would if you clicked on a link, button, or input).
If you don't want the focus to interfere with reading the page in a normal linear fashion: Don't override the focus at all. Then the browser will start at the top of the page.
We are trying to automatically check our web-application for accessibility. We are therefore looking for ways to automatically check if a certain DOM-Element having an onclick event or beeing an interactive element by definition (like a link, button, checkbox or similar) is accessible by keyboard (e.g. by pressing the TAB key multiple times).
Is there a good standard JS solution (or library) for this? If not, any hints on how this could be achieved in JS?
To simplify things, the solution would also work for us, if the elements that need to be accessible by keyboard must be known (e.g. by a list of CSS selectors).
A third party script is being used on a site I work on that replaces a few instances of <a href=""> with <a>. The links still work thanks to another part of the script, but they are no longer treated as links by user agents.
I can restore them to the tabbed navigation order by adding tabindex="0" but how can I make assistive technologies announce them as links or include them in a list of all links on a page?
Would adding role="link" help at all?
I am pushing the third party to improve their script so that the href is left intact. But in the meantime how do I best repair the damage that's being done?
I can't add either the original href or something like href="#" back to the links as the third party code will no longer do what it does. I hope that they improve their code so that I can, but for now I need to make the link accessible without the 'href'.
To make a non-href <a> behave like an <a> (and be accessible), you'd have to add role=link, tabindex=0, style it to look like a real link, and add keyboard handler code to treat Return as a click.
role="link" isn't sufficient; a screenreader may report it as a link, but without tabindex="0" and appropriate visual styles, a sighted user won't be able to tab to it in the first place, and without a keyboard event handler, only mouse users will be able to click it. (Technically screenreader users typically have hotkeys to simulate a mouse click, but keyboard-only sighted users generally don't have that option, so don't rely on it.)
Alternatively, if (big if!) the crazy script you're using allows for it, you could try shimming a 'keyboard click source' (my terminology) <a> just inside the original one: so where you have:
<a>foo</a>
you replace it with:
<a><a class='shim' href="javascript:void(0)">foo</a></a>
(The class='shim' is only needed if you need to do the event stuff described later...)
You can do this in jQuery using something like: (borrowing from Jack's answer)
$("a:not([href])").wrapInner("<a class='shim' href='javascript:void(0)'></a>")
How this works is that the inner newly-added <a ...> has a href, so it is exposed as a link and is tabbable. More importantly, if a user tabs to it and presses return, the default A behavior converts that keyboard input into a click event. This specific A has a href that returns undefined/void(0), so no actual navigation happens, but the click event will still bubble up to the original A, which gets to act on it.
(This is a neat pattern for allowing some parent element - often a DIV or similar - to handle click events, adding a child tabbable A that can source click events from keyboard gives you UI that's both mouse and keyboard usable.)
The big caveat here is that it assumes that your original script doesn't care about the target of the event. If that script does check this, it will get confused when it sees click events coming from the shim A's rather than the original As. One way to get around this is to capture and re-raise the event, which can be fiddly, and may only work on recent browsers - eg using something like:
// 'shim' class used so we can do this:
$("a.shim").click(function(e) {
e.preventDefault();
e.stopPropagation();
// the following works if listener using jQuery or is setting onclick directly, otherwise...
// $(e.target).parent().click();.
// More general way to raise events; may need alternate for IE<9
var e2 = document.createEvent("UIEvents");
e2.initUIEvent("click", true, true, window, 1);
e.target.parentNode.dispatchEvent(e2)
});
Whilst it's not very pretty, you can get at all anchors without a href attribute like so, using jQuery;
$("a:not([href])")
You can then just set the href attribute on those links to "#" and that should make them work again as regular links.
Here's a working JSFiddle
Sorry to reply with a jQuery solution...but doing this in regular JavaScript would be much more verbose.
Another way would be to give the anchors a role and then select them that way:
$("a[role='link']")
I've got an HTML link, and I want to take some action when the user tabs away from it - but only if the user is tabbing forwards through the document, as opposed to backwards.
Is there a reliable cross-browser way to detect which way the user is tabbing through the document, or indeed if they're tabbing through the document at all? I'm binding to the blur event, but that doesn't necessarily mean that the user is tabbing.
I've had a look at inspecting the value of document.activeElement, or the hasFocus attribute of the previous focusable element in the source, but:
those seem like relatively recent additions, and thus might not be widely supported, and
I'm not sure they'll be inspectable when the blur event fires, as even if the user is tabbing, I don't think the next element will be focused yet.
You will have to handle keydown event on the link itself.
$("your link selector").keydown(function(evt){
if (evt.which === 9)
{
if(evt.shiftKey === true)
{
// user is tabbing backward
}
else
{
// User is tabbing forward
}
}
});
Check this JSFiddle example that detects forward and backward tabbing on a particular link.
Sidenote: You didn't specify jQuery tag on your question al though I provided jQuery code in my answer. Since you hold Javascript as well as jQuery badges I suppose it's going to be trivial for you to convert my code to pure Javascript.
As an alternative to a good solution from Robert, maybe you can leverage tabindex attribute? Set it for your html links and other “tabbable” items. Then check it in javascript.
Solution with tabindex: jsfiddle
Side effect: Elements will also react on mouse clicks. They will behave correctly. So this might be a good side effect or bad side effect depending on your needs.