That's the thing, NVDA reads the error label correctly on Chrome but not on Firefox
example: https://material.angular.io/components/form-field/overview#error-messages
here it works (no idea why, i have the same arias): https://codepen[dot]io/aardrian/pen/WNgmGwr
I've tried:
Setting the focus on < mat-error> does the job but i doesn't makes sense because breaks navigation between fields
I couldn't find any related issue here or in its github
aria-live
is not being used properly but unfortunately, the aria-label
doc doesn't really address it so it's not uncommon for it to be used improperly.
And "improperly" might be too strong of a word. If you set aria-live
on a container and then inject new text into it, it will be read by all screen readers, including NVDA on Firefox. However, if you dynamically add a container that has aria-live
, you'll get spotty support among various screen readers and browsers. The difference is a bit subtle.
See more details in my answer for: Why the role="status" attribute doesn't work correctly?
Essentially, going from
<div>
</div>
to
<div>
<div aria-live="polite">
I'm new!
</div>
</div>
will not announce the new content in all browsers or screen readers. That's exactly what <mat-error> is doing. If you look at the example you posted on the angular site,
<mat-error aria-live="polite">You must enter a value</mat-error>
is added to the page so it will not be reliably announced. This is a bug in angular.
The codepen example you posted does work with all the examples that have live regions because
<span id="Msg01" class="msg" aria-live="assertive">
<span>Field 1 error using assertive live region.</span>
</span>
exists on the page. It is not dynamically added. Instead, the error message changes from visibility: hidden;
to visibility: visible;
so new content to the live region has been added (or more accurately, unhidden) and is announced. If the codepen example tried to add the <span aria-live="assertive">, then it would not have worked with NVDA on Firefox.
So to fix your code, you might have to add <mat-error> to your page so that it's there when the page is loaded but the contents of the <mat-error> container can be empty. Then when you inject new text into that container, it will be read.