I'm currently trying to make a DOM element with one to several child elements as accessible as possible. The element will contain illustrative content using background images in several layers. I'm currently using a child element for providing the image description as described in this informative blog post about how to label illustrative content inside of a content group. The container element may also contain other child elements containing text content.
An example element would currently look as follows:
<div tabindex="0" class="comic-panel">
<span role="img" aria-label="There is a cat sitting in the window."></span>
<div style="background-image: url(/assets/img/window.png);" class="comic-panel__layer"></div>
<div style="background-image: url(/assets/img/cat.png);" class="comic-panel__layer"></div>
<p class="speech-bubble">Meow!</p>
</div>
Testing with OSX VoiceOver, after tabbing into this element, the image description and the text is read fine, but subsequently, the following announcement is made as well:
Is it possible to update the markup of this element in a way, that this group announcement is not made by screenreaders? In almost all cases there will be nothing for the user to further explore or use inside of the element so this message would be redundant and I'd like VoiceOver to not recognise the element as a group that triggers this message.
(Moving all my comments from the comment section to the answer section since the discussion in the comments resolved the issue.)
I think there might be some misunderstanding of how a screen reader (SR) works and how a SR user navigates a webpage.
You have tabindex="0" on your <div> but the <div> doesn't have a role and is not an interactive element. The tabindex spec has a warning that says:
"authors should only make elements focusable if they act as interactive controls".
So unless the user can actually interact with the <div>, it should not have tabindex="0".
If the user can interact with the <div>, then the <div> will also need a role (see previous URL to role) so that the SR will announce the element properly and the user will understand how to interact with that element.
For non-interactive elements, SR users have lots of ways to navigate around the page so that they can access other text on the page.
One of the more common ways to navigate is by using the up and down arrow keys to walk the DOM. (Actually, you're not walking the DOM, per se, but rather the Accessibility Tree, which is basically a subset of the DOM. For example, hidden elements (CSS display:none) are in the DOM but are not in the Accessibility Tree.)
Anyway, the up/down arrow keys let the SR user get to every piece of text on the display. All your headings, paragraphs, lists, etc.
There are also single letter shortcut keys that allows the SR user to navigate to specific types of elements. For example,
H will take me to the next heading
T will take me to the next table
L will take me to the next list
B will take me to the next button
But these keys will only work if you are using semantic html, such as an <h2>, <table>, <ul>, <button>, etc or if you are using the appropriate ARIA attributes. For example, if there's a reason you can't use <h2> to make a real heading, you can still tell the SR that you have a heading by using ARIA.
<span role="heading" aria-level="2">This is a custom h2 heading</span>
JAWS and NVDA are common SRs on the PC. They'll have similar single key shortcuts that can be seen here:
JAWS shortcut keys
NVDA shortcut keys
VoiceOver shortcut keys (for the Mac, not iOS). Note that these are not single key shortcuts, like a simple H, but require the "VO" key (Ctrl+Option by default) in combination with Cmd and H.
Apple has a good tutorial on VoiceOver.
For the PC, Freedom Scientific (the maker of JAWS) has a good tutorial on JAWS.
If you have questions about accessibility, posting on stackoverflow is certainly one way to go, especially if you tag your question with accessibility and other accessibility related tags (such as wai-aria or screen-readers, as you did on this question).
Another resources is the WebAIM community. Anyone can join and you can "lurk" and just read the discussions as they come in, or fully participate.
Related
For my study project I'm currently checking an example website for WCAG 2.1 compliance.
Checking it with different tools I still get some Warnings I don't understand or know how to solve.
One of the warnings is "title on non interactive element": I have some title="" attributes on <div>, , and elements and get a Success Criterion 3.3.2 Labels or Instructions warning.
I know the title attribute is not always read by the screen reader. But if I don't expect it to, where's the problem? I even tried to add an aria-label="" with the same content as the title but still get a warning for the title attribute.
<div class="criterion_secion" id="criterion_214" title="Success Criterion '2.1.4 Character Key Shortcuts'" aria-label="Success Criterion '2.1.4 Character Key Shortcuts'">...</div>
I believe that the warning is given because it’s not expected to have a label or a title on a non-interactive element, like a div.
A div is by nature a non-interactive element. We could make it interactive through the tabindex attribute or by giving it a role. However, I would advice not to do that and just use the div for what it's intended, as a container.
It make sense your tool are flagging title on non interactive element as a warning, because a lot of users can't access to your content in the title attribute. A warning doesn't mean it's automatically a failure.
The aria-label attribute on a div (without role attribute) is useless. This element have no semantic and it's not supposed to have an accessible name.
ARIA & Tooltips: 2 commonly misunderstood attributes
There is a very easy solution to this issue: remove both title and aria-label attributes and include their content that reads "Success Criterion '2.1.4 Character Key Shortcuts'" inside the DIV element, if not already included.
aria-label
The aria-label attribute defines a string value that labels an interactive element.
First of all, ARIA is for the screen readers only and it overwrites the accessible name of the element.
For example,
<label for="name" aria-label="surname">Name</label>
<input id="name" type="text" />
will be announced as "surname" and the screen reader user will never understand it is for the input field that collects users' "name".
As for the non-interactive elements, a paragraph never needs any aria-label for the simple reason that you can always include whatever information you want inside it. Besides, it may not be read or may confuse your users as a non-interactive element that acts like an interactive one.
It is also important to know that repeating what is already available as text with an aria-label is simply a nuisance, making the screen reader say the same thing twice or even thrice sometimes, along with a tooltip.
Tooltips
Tooltips are intended for sighted users. They provide some extra information that was not made available elsewhere. Examples from Mozilla.
It is helpful to understand these:
Tooltips are not accessibility features
Repeating what is already available as text using the title attribute helps no one and annoys screen reader users. It is simply bad practice.
Here is a comprehensive resource that will probably make you think twice before using another tooltip: If you want to hide content from mobile and tablet users as well as assistive tech users and keyboard only users, use the title attribute.
On my web page, I have a div (shown below), which has text in it that I want to be read by a screen reader.
HTML
<div tabIndex={0}>
"text needs to be read"
</div>
I can hear the text is read without even providing the aria-label. However, I heard "text needs to be read group". I would like to know how can I avoid it saying "group"? I did not put a group role for the div tag.
Another example
This is another example that describes the problem much cleaner
<span class="jw-icon jw-icon-inline jw-button-color jw-reset jw-text-live" tabindex="-1" data-clicked="true">Live</span>
Run the above snippet in any browser. It makes the screen readers to announce it as "Live, group".
Is there any way to mitigate this behaviour. Expected behaviour should be like the screen readers should read it as "Live"
Lots of things going on here.
First of all, all text on a webpage is available to a screen reader and does not need tabindex="0" to make it available to be read. Screen readers provide lots of shortcut keys to navigate to different types of elements (headings, tables, lists, etc). For elements that don't have a direct navigation key, the screen reader user can use the up/down arrow keys to walk the accessibility tree (similar to the DOM).
Secondly, regarding tabindex="0", it should only be set on interactive elements. The tabindex spec says:
authors should only make elements focusable if they act as interactive controls or widgets. In addition, authors should ensure that these focusable elements have an appropriate ARIA role attribute.
And regarding ARIA roles in the second sentence in the spec quote, if your element does receive focus, if it's not a natively focusable element (such as a <a> or <button> or <input>), then it needs to have an appropriate role so that the screen reader user will know how to interact with it.
And related to this, you mentioned aria-label. The aria-label is only honored on elements that have an appropriate role. See "2.10 Practical Support: aria-label, aria-labelledby and aria-describedby".
So given all that, it's a little difficult to answer your question because your simple example is not specific enough. A <div> without a role should not read as "group". Group is usually role="region" (or <section>). The behavior you're hearing may depend on what browser you're using, what screen reader, how you're navigating in with the screen reader (tab or arrow or quicknav key).
Context: Educational ebook (HTML + CSS) publishing
I have a composition title where I have a sentence like this:
<p>This is <del>correct</del> <ins>incorrect</ins></p>
And it is important that the user knows that some text is being deleted and some text is being inserted. I also have a related scenario where text has a highlight applied that has semantic meaning. For instance:
<p>This is an <span class="highlight-blue">adjective</span> and this is a <span class="highlight-red">noun</span>. </p>
I was recommended to use role="region" + aria-label for these situations by an accessibility consultant.
For instance:
<p>This is an <span role="region" aria-label="adjective" class="highlight-blue">adjective</span> and this is a <span role="region" aria-label="noun" class="highlight-red">noun</span>. </p>
The flexibility is necessary here because we are using a standard CSS for all of our titles and sometimes a highlight-red might indicate passive voice or it might indicate a noun, etc.
I have seen in other questions on this site that it is not allowed to use aria-label on span (or div) elements. Also using Chromevox, I have found that the reader will read the aria-label but not the text inside the aria label. (I do not have access to other screen-readers for testing.)
So my question is: What is the best way to have the semantic meaning of these inline elements read to the screen reader user?
Non-viable options
Pseudo-element with CSS hiding. I've seen solutions where you can create a pseudo-element and then hide it offscreen using CSS. When you hide content off-screen, Kindle encounters issues, dropping large chunks of text after the off-screen content, so this is not a viable option.
I would not make the highligting marks a region. That makes them a landmark, which are used to navigate to different areas on the page. The more landmarks you have, the less useful they are (because you'd have to navigate through a bunch of them to get where you want.).
There's a nice article on making highlights and other editing symbols accessible on "Short note on making your mark (more accessible)"
it is not allowed to use aria-label on span (or div) elements
That's not quite accurate. aria-label is a global attribute and can be set on any element. However, the label might be ignored if set on a <div> or <span>. See "2.10 Practical Support: aria-label, aria-labelledby and aria-describedby". In particular, the third last bullet point:
Don't use aria-label or aria-labelledby on a span or div unless its given a role.
So if your <div> or <span> has a role that is appropriate, then the aria-label will be read. But don't assign a role just to get the aria-label read. The role has to make sense.
I'm adding various Accessibility standards to our enterprise platform UI framework. We use a web client, DOM elements, etc. We render all of the framework in the DOM, but widgets in the framework can (and have for years) been put together in non standard ways by customers to build out various pages of their UI.
I've managed to cover and handle much of the specifications (I think), but I have a specific case, where we have "texty labely widgets" that are used to describe various "input / formlike widgets". Their only connection as far as the DOM goes is a common parent "container" element, a variable distance up the tree.
The ARIA guidelines I'm coming across (which at any point I may have misunderstood) suggest I need to use aria-labeledby="id_of_text_label_widget" on the actual form element. Meaning what I have now is:
<div id="parent_label_value_widget_001">
<div class="inputLabel">This is visible Label Text</div>
<div class="various_other_junk_in_here"></div>
<div class="some_wrapper_around_the_input">
<input id="I_am_the_form_input_in_question_with_a_very_long_id" value="42">
</div>
</div>
I could easily add the aria-labeledby attr to the input, but it means I'd need to add an id to the inputLabel element. And while this seems like not a big deal (it's slightly more complicated because what you see in the DOM is the result of a far more complicated render cycle from a WYSIWYG editor of disconnected widgets), it happens to be, with no possibility for change, that our ids are incredibly long already. Due to huge pages, sometimes tens of thousands of fields and nested dynamic things, etc
Our Ids make up 60% of our payload. And I'd effectively have to double that chunk by adding a new id to every label element, and our content isn't gzipped. So that's what I'm trying to avoid. I actually also don't want to do it for other reasons, as the label widget and the input widget actually know nothing about one another, so I'd have to write some extra render logic to have the input widget pull the id from the sibling label widget.
My question is: does anybody have any other solutions?
Things I've imagined:
A. Is there some technique using aria-label, where I could label the parent container and have screen readers know how to link the internal label and input?
B. I could duplicate the label text from the label widget onto the input widget and use aria-label="duplicated text". I could do this server side with some pain, or client side with some clumsy walking logic, but would rather avoid the duplication, and the extra logic. But if I do that, then do I need to aria-hide all the existing label widgets?
C. Is there some shorthand for <label for=""> or aria-labeledby="" where instead of an id, it can reference elements by css selector, or proximity? (Dreaming, I know), but it's a shot.
D. Make the user opt in to aria support, and only then do they get the doubled package size. (yeah, I know gzip would solve alot of this, but it's a long story why it's not in place).
The short answer is that <input> elements need some kind of label and that label has to be directly associated with, or "tied to", the <input>. "Proximity" is not a direct association. That is, just because a label is "close" to the input in the DOM, that doesn't tie the two elements together.
Some screen readers will try to look for some text to use as a label if one is not explicitely found, but that usually involves going to the previous sibling of the <input> in the DOM and if that sibling has some kind of text associated with it, then treat that like the label. Sometimes it works and sometimes it doesn't. I would not rely on it.
For example,
<label>password</label>
<p>should contain upper and lower case letters, a number, and a special character</p>
<input>
In this case, the "should contain..." text will be treated as the input's label, which is wrong. It doesn't matter that there is a <label> element prior to the <p>. There is nothing in the DOM tying the <label> to the <input>. The above example should be written as:
<label for="pw">password</label>
<p id="rules">should contain upper and lower case letters, a number, and a special character</p>
<input id="pw" aria-describedby="rules">
This associates both text elements with the input. The <label> is tied directly via the for attribute (and the ID on the <input>) and the description of the password is tied via the aria-describedby on the <input>.
So the first choice of labelling an input should be with native html, if possible. Use the for attribute of the <label>.
Another way to label, as you noted, is using the aria-label or aria-labelledby on the <input> itself. While this will give the input an accessible name for screen readers, it won't help sighted users. The aria-label is not a visible thing. However, in your case, it looks like there is already a visual label (even if it's not officially "tied" to the input).
So, to comment on your four proposals (A-D):
A. You can put aria-label on the parent container but the <input> would still need to be told to look at the parent to retrieve the label, and that's done with aria-labelledby on the <input> (and would require an ID on the parent so you can point to it.).
B. If you put the aria-label directly on the <input>, then yes, you should set aria-hidden="true" on the visible label, otherwise a screen reader user can navigate to the visible label text and then navigate to the input and hear the same text again. But that's an odd solution. If the text is already visible, the best thing is to put an ID on the visible text and associate it with the <input> via aria-labelledby.
C. Worth a short, but no.
D. This is a friendly place so all ideas will be considered, but please do not do this. Do not segregate different types of users or force people to opt-in to an accessible site.
It sounds like your main argument for not creating an accessible solution is the size of your page. Not to be dramatic, but that wouldn't hold up in court. That is, if your site ended up being the defendant in litigation, arguing that you didn't implement accessibility because you didn't want the page load to be larger would not be a valid reason. That's just an implementation problem on your end.
So I was able to get my page working just fine with the NDVA screen reader, however, when testing in JAWS, it tabs to the span, but doesn't read the text.
<span tabindex="0" title="whatever">whatever</span>
UPDATE:
What I am trying to achieve is a I have a few elements which expand/collapse certain sections of the site I'm building. These functional elements, however are not links.
Reponse to #discojoe (thanks for the response)
Adding a TABINDEX="0" attribute will insert the SPAN/DIV element into tabbing list in natural order (whereas by default, they're usually not added to the tabbing list). This allows screen readers to tab to that element, and is working just fine. Specifically, my problems is JAWS will just tab to that element, it just doesn't read it.
I agree, using TABINDEX="n" (where n > 0) is a bad thing which messes with the natural order of the tabbing list, and I am not doing that.
Also, you can use TABINDEX="-1" to remove an element from the tabbing list if it's placed in there by default (example an A or INPUT tag).
I have already tried using tags, however, when user hits enter on this link (to trigger the onclick event), it does something (not quite reloading, but kinda re-initializing) to the page which delays the animation associated with that element. I find that to be a bad experience to both normal and disabled users.
using the # tag in the A tag adds the hash tag to the page title in IE.
Additionally, using A tags makes the screen reader read out "LINK" before/after each element, and since they're not actually links, I feel this is negative impact on accessibility.
I would first want to know why you are using a span element and not a standard a href element? What is it you are wanting to achieve? It may help if you can provide more context\code.
I've just tried this and am getting the same issue; whilst I can arrow through the document and have a span read out to me, I cannot then tab to it and have it read out.
Using something instead like
Whatever
works fine.
There are additional problems around using the tabindex attribute, specifally for keyboard users. On a page that users the tabindex attribute, the tab focus order will first of all go through all of the elements with tabindex specified, and then run through all the elements without it, in source code order.
A good general rule is to either use tabindex for all keyboard accessible elements, or for none of them, to get around this problem.
I realise in this case, you are likely using tabindex to just provide keyboard accessibility for this one item, so this issue may be irrelavant if you use the a href approach mentioned, but I wanted to mention it for completeness
First of all, reading "link" before such elements does not impact accessibility in a negative way, I'd say, it's quite opposite: you warn the user that he/she can click the element in such a manner.
Here you have a couple options:
Use quite a lot of ARIA: add the link role to your span elements, properly code your expanding/collapsing menus (with corresponding ARIA roles and states).
Use <a href="#" as suggested by #discojoe but add event.preventDefault() (in jQuery) or return false; (in vanilla) so the page would not reinitialize.
If you need more suggestions, please post some code or a link to your page.
Use anchor tag for screen reading simple text related works. You can simply do :-
<a href="javascript:void(0);" title="What you want to be read by jaws></a>
That's it. I tested it with JAWS.