0

I am building a React site and have to support accessibility across browsers.

On my site I have inputs and I perform the validations only on blur, if the input is not valid - an error message is inserted after the input.

My problem is that the screen reader skips this new error element and jumps to the next one - it seems that the reader calculates the next element when it's focused on the previous one (in my case the input). and therefore when I "tab" and blur out of the input it goes to the next tabbable element - and skips the new error.

The new error element that's getting skipped has all required attributes, (it is getting focused if I do shift + tab from the next element that was reached after the input). I have also tried adding aria-live="assertive" to the new error message element but it doesn't help.

Any solution for this?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Adam Mor
  • 79
  • 1
  • 8
  • Are you actually using "Tab" to try and get to the new element or is that just poor phrasing in the question, as the new error message element should not be focusable and therefore not receive focus. What screen reader are you using and can you put a fiddle together to demonstrate the issue? – GrahamTheDev Oct 14 '21 at 16:42
  • You can find a primer on accessible form validation here: https://webaim.org/techniques/formvalidation/#error It sounds like you are using the "inline error" approach as described on this page. – Josh Oct 14 '21 at 17:58
  • The tabbing behavior you're describing sounds to me like "focus mode". This is a feature of nearly all screen readers. https://dequeuniversity.com/screenreaders/nvda-keyboard-shortcuts#nvda-browse_focus_modes – Josh Oct 14 '21 at 17:59
  • Please provide the markup you are using. You can use Stack Snippets (icon is `<>` in the toolbar) to do so, and provide people with a runnable example here on Stack Overflow. There are a number of questions about accessible input validation on Stack Overflow already; have you read any of those? For example, from the Related list to the right: [How to make inline errors read aloud by screen reader tools?](https://stackoverflow.com/questions/53167195/how-to-make-inline-errors-read-aloud-by-screen-reader-tools?rq=1) – Heretic Monkey Oct 14 '21 at 19:36

2 Answers2

2

The aria-invalid and aria-describedby recommendations by @jongibbons is good but the actual announcement of the error message when it's added should be handled by aria-live. You mentioned you tried aria-live but that it didn't work. It might depend how you were trying to use it.

If you try to add that attribute dynamically when the error message is generated, then it won't work. aria-live must exist on the page before you add text to it. For example, the following won't work:

Before the error:

<input>

After the error

<input>
<div aria-live="polite">this is the error message</div>

If the <div> is added dynamically, it won't be announced even though it has aria-live.

Instead, your code should look like this:

Before the error:

<input>
<div aria-live="polite"> <!-- empty area for error message --> </div>

After the error

<input>
<div aria-live="polite">this is the error message</div>

In this case, "this is the error message" will be announced by screen readers when the new text is injected into the page.

And as @jongibbons said, associate the error message with the input field via aria-describedby.

<input aria-describedby="foo">
<div id="foo" aria-live="polite"> <!-- empty area for error message --> </div>
slugolicious
  • 15,824
  • 2
  • 29
  • 43
  • Thanks @slugolicious! What you say makes sense, but strange enough it's working now (error is being added on the fly with aria-live="assertive"). I suspect SR issues since I faced some diffs between NVDA and ChromeVox. I also found more references here: [link](https://stackoverflow.com/questions/27546070/difference-between-aria-live-assertive-and-aria-live-polite). It turns out that aria-live="assertive" is strong enough to interrupt user action while aria-live="polite" will be announced only if user is not performing an action. and maybe assistive technology settings too?! – Adam Mor Oct 20 '21 at 22:35
  • 1
    If you are dynamically adding an `aria-live` region and it's currently working, you might be getting lucky. I wouldn't depend on that behavior. The code example I gave with an empty live region and then injecting text will always work. I would also caution against using `assertive`. I rarely use it because it can *potentially* clear other pending screen reader announcements. Usually `polite` is sufficient for most cases. – slugolicious Oct 21 '21 at 14:42
  • 1
    *""polite" will be announced only if user is not performing an action"* is not quite accurate. `polite` will always be announced but it's queued up to be announced **after** the user is done listening to the current announcement. – slugolicious Oct 21 '21 at 14:43
  • Thanks for the important Info! helped me understand better many "mysteries"... Isn't it strange that those things work by "luck" as you said ?! I would expect strict behavior.. Its so confusing. – Adam Mor Oct 23 '21 at 16:20
1

For the behaviour you describe to be accessible, you want to look at using the aria-invalid and aria-describedby attributes.

When a field has an error, toggling aria-invalid on the <input> from false to true will cause screen readers to announce the change in state.

Adding an aria-describedby relationship between your <input> that's in error and the HTML element containing your error message should then also cause the screen reader to announce the error message.

<label for="email">Email address</label> 
<input type="text" name="email" id="email" class="error" 
  aria-invalid="true" aria-describedby="email-error">
<p class="error-message" id="email-error">
Error: This doesn't look like a valid email address
</p>

Here's an example on MDN with code that might match what you need: Using the aria-invalid attribute

Jon Gibbins
  • 887
  • 7
  • 14