I am working on accessibility issue.
I have a spinny/loader which appears on screen when data is getting loaded.
<spinny aria-live="polite" role="alert" aria-label="Loading Page">
So when the spinny appears on screen, screen readers give me alert that spinny is loaded.
Now I want that when the spinny goes away from screen i want the screen reader to provide message such as data loaded or something like that.
I have tried aria-relevant, aria-atomic etc but nothing seems to have worked.
First off, your code sample is specifying conflicting information. Using role="alert" gives you an implicit aria-live="assertive" but you are also specifying aria-live="polite". I would recommend removing role="alert". Having aria-live="polite" is sufficient.
However, if you remove the role from <spinny> (which I'm guessing is a custom html tag?), then your aria-label may not be honored because aria-label'ed things often need a role in addition to the label in order for the label to be read by a screen reader. See "Practical Support: aria-label, aria-labelledby and aria-describedby"
But, I think you might be using aria-label incorrectly anyway. Your live region should look something like:
<div aria-live="polite" class="sr-only" id="myspinny"></div>
(See What is sr-only in Bootstrap 3? for the "sr-only" class. It will visually "hide" the <div> so that any text you put inside it will not be visible to the sighted user but will still be available to screen reader users.)
When data is loading, you should inject text (via javascript) into "myspinny" so that it looks like:
<div aria-live="polite" class="sr-only" id="myspinny">Loading Page</div>
Since the <div> is a live region, the text ("Loading Page") will be announced.
When the data is finished loading and you want to remove the spinner, inject new text into "myspinny" so that it looks like:
<div aria-live="polite" class="sr-only" id="myspinny">Data Loaded</div>
and the screen reader will say "Data Loaded".
Related
I am using the javascript library vex to output dialogs like this
When I used this with a screen reader (narrator), that text is not read so I tried to change the javascript inside vex that manipulates the DOM.
The resulting DOM became like this
<div class="vex vex-theme-default" role="dialog">
<div class="vex-content">
<form class="vex-dialog-form">
<div class="vex-dialog-message" tab-index="0"
aria-label="Login failed">Login failed!</div>
<div class="vex-dialog-input"></div>
<div class="vex-dialog-buttons">
<button type="submit"
class="vex-dialog-button-primary btn vex-dialog-button vex-first">Ok</button>
</div>
</form>
</div>
</div>
but the message "Login failed" is not read even with this markup.
Why not?
(I have also called .focus() on the div with the class vex-dialog-message).
The screen reader will instead continue to read the text after the button that was pressed when trying to login (that is running an ajax request that tries to login so the document is never reloaded).
This is what role="alert" is for.
It will interrupt a screen reader (as it is the equivalent of aria-live="assertive") with any immediately important information.
As this is a dialog you may instead want to look at role="alertdialog" to replace your role="dialog".
Additionally when you focus the alert don't make the "Login Failed!" text tabindex="0".
Instead use tabindex="-1" so that you can still focus it programatically but it does not end up in the focus order of the page.
The pattern you currently use will be tricky (not impossible) to get right as your "OK" (submit) button is within a form, so this will send screen readers into "forms mode", which behaves differently from normal reading mode.
As such if you are able to create a custom component there is a great writeup from deque on how best to implement an alertdialog
An example of the markup used there is as follows, notice the use of aria-describedby and aria-labelledby to maximise the chances of the alert being read correctly:
<div role="alertdialog" aria-labelledby="alertHeading" aria-describedby="alertText">
<h1 id="alertHeading">Warning! Street Address Mismatch!</h1>
<div id="alertText">
<p>The street address you entered does not match the Postal Code Data.</p>
<p>Is this the correct format: 12345 Main St. Blvd.?</p>
</div>
<button id="yes">Yes, Format Is Correct</button>
<button>No, Edit Street Address</button>
</div>
I am trying to implement the notification component that will show the list of the items and will be opened by clicking on the notification icon on the fixed navigation bar on the top. I don't think it's a menu bar. Because the menu provides the actions that can be performed and it can also have a sub-menu.
https://www.w3.org/TR/wai-aria-practices/#menu
Can anyone let me know what should be the aria-role of such kind of components?
Below is the code sample. I will open the template dynamically by clicking on the notification icon button:-
<button aria-label="notifications">
<mat-icon class="mr-md">notifications</mat-icon>
</button>
<!-- Notification template -->
<div class="notifications__item">
Notifications
<li *ngFor="let notification of notifications" class="notifications__item">
<mat-icon class="notifications__icon material-icons-round">
{{ notification.icon }}
</mat-icon>
<div class="notifications__content">
<div [ngClass]="{ 'notifications__warn': notification?.type }">
<span>{{ notification.title }}</span>
</div>
<div>{{ notification.description }}</div>
</div>
<small class="notifications__caption">
{{ notification.duration }}
</small>
</li>
</div>
There are still a lot of things to consider that your example doesn't cover, so this isn't a complete answer, it is just pointing you to the relevant WAI-ARIA depending on what route you take.
The button
The first thing to consider is the button. You need to tell screen reader users what state it is currently in. For this we use aria-expanded to indicate whether the item it controls is currently opened or closed. (aria-expanded="true" for open, aria-expanded="false" for closed.)
At the same time we want to indicate what item this button controls (as the notification list isn't 'owned' by the element - for example if it was an <li> with a nested <ul> in a menu then the list would be 'owned' by it).
For this we would use aria-controls or aria-owns and point it to the ID of the element it controls. For the difference between them see this stack overflow post as a good explanation, in this example I would say it is aria-controls but yet again depends on your implementation and positioning in the DOM.
With regards to the button itself and where it sits in your menu, this is still considered navigation so it should sit within your <nav> element. However if this sits outside of your navigation along with say a 'help' and 'account' section you may consider those items part of a toolbar. (yet again I would say it doesn't apply here but something to look at)
Also it doesn't appear to be applicable here but if you include any links etc. within the 'popup' / modal that shows the notification list (i.e. a 'view all notifications' link), you should consider aria-haspopup="true"
The notification list
Right so we have a button pointed to the container (don't forget to give the container the relevant ID for aria-owns or aria-controls). Next what about the container itself?
Well in this example it appears that the container should be treated like a modal.
So for this reason you need to consider:-
trapping focus in the modal,
close with Escape,
returning focus to the button that activated it on close,
providing a close button that is accessible by keyboard,
a title for the modal (even if it is visually hidden)
What I would recommend is add some of the accessibility features above, try it with a screen reader and keyboard and see if it is easy to use. Once you have decided on your pattern ask some more questions on specific use case issues as the above is general guidance.
A few things to consider based on your markup
Additional things to consider from your example:-
use aria-hidden="true" on your icons, they don't add anything for screen readers (assuming your notification.title is descriptive).
For the notification title consider making it a relevant heading (<h2> - <h6> depending on position in document.
Don't forget to add some visually-hidden text that describes the warning level (I can see you have some form of colouring / distinction in [ngClass]="{ 'notifications__warn': notification?.type }" - expose the same info to screen readers.)
You currently have a <li> within a <div> - maybe change the outer <div> into an <ul> so it is semantically correct (<div class="notifications__item"> into <ul class="notifications__item">)
I hope the above is useful to set you on the right track, a lot to read but after reading the linked articles you should be able to make a better decision on what pattern you are using (as I didn't even mention making this a sub item within your menu) and can then ask some more questions on specific details you don't yet understand.
final thoughts / tips
test with a screen reader - this is the biggest tip I can give on working out how WAI-ARIA works and interacts with things.
Also if you are ever in doubt as to whether a WAI-ARIA attributre is applicable it is better to not include it.
Incorrect use or WAI-ARIA is actually worse than not including it at all so make sure you understand when to use an attribute reasonably well before implementing it. If I am ever unsure (as it still happens to me!) I tend to look at 2 or 3 examples of it in use and see if my pattern fits the examples I looked at.
I need to have a screen in my app which all of it's content will be read using the screen reader automatically.
I tried to add role="dialog" aria-live="assertive" aria-atomic="true" and it didn't make it.
I also tried to use role="alert" aria-live="assertive" aria-atomic="true" it did read it, but using 'alert' as prefix.
How can I make it happened using no prefixes and additional info ?
I believe the document role is the correct one to use in your case. From MDN:
Generally used in complex composite widgets or applications, the document role can inform assistive technologies to switch context to a reading mode: The document role tells assistive technologies with reading or browse modes to use the document mode to read the content contained within this element.
You should include tabindex="0" on the element in which you wish to be immediately read, and use JavaScript to set the focus to the element.
Update
I tested the following code in Mac/Chrome, version 79.0.3945.88, and removed the tabindex attribute as well as all JavaScript. VoiceOver immediately read the contents of the document in its natural order.
<div class="container" role="document">
<p>
Read this first.
</p>
<p>
Read this next.
</p>
</div>
I did a screen capture of the VoiceOver utility as it was reading the above HTML to show it working on page load (forgive the Giphy Capture bit at the beginning of the gif).
If this really is something like a dialog - which means it consists mostly of operable content (UI controls such as buttons) then the non-operable content will not get announced by default. You can solve this if, on the thing with role="dialog", you have aria-labelledby pointing at its heading, and aria-describedby pointing at all the ids (space-separated) of the elements inside that you want read-out when it opens.
The markup might look like this:
<div role="dialog" aria-labelledby="dialogheading" aria-describedby="foo bar">
<h2 id="dialogheading">Let's have a dialog</h2>
<p id="foo">lorem ipsum</p>
<p id="bar">rhubarb rhubarb</p>
<button>yadda</button>
<button>yoda</button>
</div>
If there's really a lot of non-operable content, or if there's no operable content, role dialog is the wrong thing. If the context for this 'screen' is in forms/application mode use role=document instead, and make sure it has a tabindex so you can give it focus, which should switch the screen reader to browse mode.
I'm working on fixing some accessibility issues on a web page. I have this div that acts as a dialog, and inside at one point a div containing a loading animation and a text "Working..." is displayed.
I am unsure as to how to label these two items in order to correctly notify the blind user that there is a progress animation and that it's working and he should wait.
<div id="loading" style="display: none;">
<div class="mgBot15"><span class="txt16" role="alert">Working...</span></div>
<img src="loading.png" role="progressbar" aria-busy="true"/>
</div>
I tried adding the role and aria-busy properties to the img (also to the parent div, at first).
When this div appears (by changing the display style property), it correctly reads "Working..." but I hear no indication that it's busy and that the user should wait, am I missing something?
I've looked all over for examples for loading animations, to no avail so far.
Note: I'm using NVDA as a screenreader to test.
Thanks
The best solution I could come up with was using role alert, and aria-busy="true".
<div id="loading" style="display: none;">
<div class="mgBot15"><span class="txt16" role="alert" aria-busy="true">Working...</span></div>
<img src="loading.png" alt="loading" />
</div>
I believe the most sensible approach would to use the combo
aria-busy="true" aria-live="polite"
The reason for that is because some pages might have a lot of separate loaders (let's say one for each component, not a single loader for the whole page) and it you use aria-live="assertive" or role="alert" it will be very intrusive and each of the loaders will get called out.
The correct role to use here is progressbar as the original question used. Other roles like alert may work, but they are less specific, meaning assistive technology may present the information in a less ideal manner.
There are a few issue with the original question's example, though:
If you wish to have the text be announced in the same as an alert is, aria-live="assertive" should be used rather than the alert role. That aria-live value is what causes the screenreader to announce the text when it does for an alert.
The text to be announced should be set on the element with the progressbar role using the aria-valuetext attribute. It should not be set solely on a separate adjacent element. If it needs to also be included in another element for presentational reasons, that element should have aria-hidden="true".
Per the spec, aria-valuemin and aria-valuemax are to be specified even when the progress is indeterminate (like a spinning loading indicator). These could be set to 0 and 100 respectively as simple placeholders implying a percentage.
When the loading is complete, the aria-valuenow could be set to whatever was used for aria-valuemax, and aria-busy can be set to false.
This leads to one potential alternative to the original question:
<div id="loading" role="progressbar" aria-valuetext="Working…" aria-busy="true"
aria-live="assertive" aria-valuemin="0" aria-valuemax="100">
<div class="mgBot15" aria-hidden="true"><span class="txt16">Working...</span></div>
<img src="loading.png" alt="" />
</div>
After a day of fiddling with a similar issue, I was able to finally get this working with a lot of reading and experimenting. I'm using NVDA for a screen reader.
<div class="loader" show.bind="isLoading" role="alert" aria-label="Loading"></div>
The following attributes were key: role and aria-label.
Above example makes NVDA announce "Loading alert" once isLoading becomes true. Important to note is that NVDA pronounces the aria-label value, followed by "alert". Using roles "log" or "status" did not end up in any announcement.
Bootstrap used role="status" like this :
<div class="spinner-grow text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
and in MDN it said :
The status role is a type of live region and a container whose content
is advisory information for the user that is not important enough to
justify an alert, and is often presented as a status bar. When the
role is added to an element, the browser will send out an accessible
status event to assistive technology products which can then notify
the user about it.
There's a good article I came across that explains what needs to be done for this scenario Loading spinner accessibility
The spinner should be included inside the container. Its visibility can be toggled in relation to the aria-busy attribute. They should always be opposites, i.e, if currently loading, section[aria-busy="true"], .tn-spinner[aria-hidden="false"], once the content is loaded, toggle to false and true respectively.
I have an image
<img src="sample.jpg" alt="sample">
which is reading as LINK GRAPHIC by JAWS, I have to make JAWS to read as Sample Image.
Why would you try to make JAWS read something in particular?
The important part is the information and content your page is giving to your users. What's the purpose of this content?
Only then, verify that screen readers are reading out the information in a correct manner. a>img is a link graphic; JAWS is correct.
Ryan's Notes
There are two ways to maybe get it like that:
Make sure the user is in expert mode with specific settings. Asking a user to adjust their settings so your site reads nicer, probably won't happen.
Write a JAWS script to interpret <a><img> a certain way. _See #1, _
Wrap your text with invisible content markup and hide img-tag from JAWS via aria-hidden:
<a href="#">
<div style="font-size: 0; line-height: 0;">JAWS reads this text</div>
<img src="sample.jpg" alt="sample" aria-hidden="true">
</a>
More ways to create invisible content can be found here:
https://webaim.org/techniques/css/invisiblecontent/