skip to Main Content

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


  1. 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 of assertive 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.

    The toasts are also set to autohide after 3 seconds (I have been told this is not a good thing in an accessibility perspective).

    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.

    Login or Signup to reply.
  2. In fact, it’s quite a good idea to have a special element to make screen readers speak such ephemeral messages.

    • As you have observed, it doesn’t work with some screen readers when aria-live attribute isn’t present from the start and/or when live regions are added dynamically in the page after page load
    • Remove the element and/or clear the text make some screen readers cut off speech immediately if they haven’t finished speaking, and you have no way to know if your messages is currently being, hadn’t yet been spoken, or is already done.
    • Some screen readers have difficulties and/or can have strange behavior when the structure of the content inside the live region is becoming too complex. You need to stay rather simple to ensure consist behavior across screen readers / browsers / OS.

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search