I am trying to make a toast message component accessible (to comply with WCAG 2.1 AA standards) in Angular. The toast message has 4 types (Success, Warning, Error, Info) and each type has a dynamic message.
The html of the toast component looks like this,
toast.component.html
<div aria-live="assertive" class="toast-wrapper toast-error">
<span id="toast_heading">{{toast.heading}}</span>
<sapn id="toast_message">{{toast.message}}</span>
</div>
app.component.html
<app-component>
<toast-component *ngIf="showToast"></toast-component>
</app-component>
The visibility of the toast is controlled by the showToast
variable and there are no multiple toast components showing up at the sametime as well. The toasts are also set to autohide after 3 seconds (I have been told this is not a good thing in an accessibility perspective).
However the toasts were not read by the screen reader (NVDA) I use when they are shown (In chrome, did not test in other browsers).
After searching about this I found out that the aria-live
attribute has to be present when the webpage is loading for some screen readers to pick it up and since the toast-component
is only being generated when a toast is needed, it is not being read by the screen reader.
I also found this webpage https://terrillthompson.com/tests/aria/live-scores.html where in the "Game 3" example the author has used a separate status div
to read the score and set role="presentation"
for the scoreboard.
I implemented it in my app like this:
toast.component.html
<div role="presentation" class="toast-wrapper toast-error">
<span id="toast_heading">{{toast.heading}}</span>
<sapn id="toast_message">{{toast.message}}</span>
</div>
app.component.html
<app-component>
<div aria-live="assertive" class="visiually-hidden" id="assertive_div">
{{toast.heading}} - {{toast.message}}
</div>
<toast-component *ngIf="showToast"></toast-component>
</app-component>
Now when I trigger a toast message it is being read by the screen reader eg: "Error – cannot delete the selected user" , "Successfull – 15 records were saved".
The question I have now is this approach of having a separate div
for screen readers to read as the toast message acceptable instead of reading it through the actual toast component ?
Plus, any areas to improve ?
2
Answers
It’s true that live regions should exist on the page and not be dynamically added.
See my answer about live regions.
There’s nothing wrong with having a separate
<div>
to contain the live text that will be announced but I try to avoid that if I can mainly from a coding efficiency perspective. I don’t like to have repeated blocks of text if I can get it to work with one block of text.A few other things, I would recommend using
polite
instead ofassertive
for the live region. Assertive should be reserved for critical messages that absolutely have to be announced. Polite should be used in almost all cases.I agree with that this would cause an accessibility issue. It would fail 2.2.1 Timing Adjustable.
Toast messages, in general, are not a great UX. If you really want to use them, make then for messages that are not important so if the user doesn’t see them, it’s not a big deal. It’s usually better to have a message area appear and not automatically disappear but have an X-close button on them.
In fact, it’s quite a good idea to have a special element to make screen readers speak such ephemeral messages.
Using a separate element especially made for screen reader messages, can therefore be quite a good idea.
It’s the occasion to put that aria-live element directly at page load, simplify the structure of the text to be spoken, and unhook from the purely visual behavior such as hiding after 3 seconds.
You can, if you want, put that special element off screen.
There is just a small drawback, but it stays acceptable, and can even be useful in some circumstances: the last message spoken stays and is reachable forever until another one replaces it.
However, I would forget about the assertive mode and change to polite.
Your example messages such as "15 records were saved" or "cannot delete the selected user" aren’t sufficient for being assertive, even the error message.
Don’t forget also that assertive means interrupting everything, so if you have several messages poping at the same time, only the last one will be read while all previous ones are skipped. So if you stay assertive, you will also need to prioritize or reorder messages, and this raise that other not so simple question of deciding which single message is the most important in which situation. Believe me: stay away from that and keep it simple, be polite.