WAI-ARIA role=alert on Static Warning Messages & Stopping VoiceOver for iOS from Speaking CSS Generated Content Icons with aria-hidden

Non-Disappearing Alert

Testing a client travel site I see a static weather travel alert warning that is very visually marked as important on the screen but the screen reader user would have no idea of its importance because there are no accessibility API semantics communicated.

screenshot of travel alert example

CSS Generated Icons Cause VoiceOver for iOS Bugs

There is also a CSS Generated Content glyph icon to indicate visually that this is a warning or error message. The text Travel Alert: is red and bold but it has no heading semantics.

I think the string “Travel Alert:” serves as the text alternative for the warning icon itself so you don’t need additional alt text.

VoiceOver for iOS has a bug or a feature, not sure, that causes it to speak “Face Screaming in Fear” when focused on this bootstrap CSS generated warning icon! That’s crazy right! 🙂 I’m serious go test it out. http://pauljadam.com/demos/role-alert.html

aria-hidden=true Prevents VoiceOver for iOS from Speaking CSS Generated Content Icons

Bootstrap code for this had aria-hidden=true already correctly applied to the span that generates the icon but I’ve seen this bug out in the wild on many client sites so glad to see the solution works! Try the before and after example.

voiceover displaying css generated icon but not speaking it

See Details Link Purpose Determinable?

Link Purpose is another issue where a screen reader user could not determine the purpose of the See Details link if they just TAB to the link and only hear “See Details, link”. What exactly are the details I’ll be seeing if I click the link? I recommend placing the aria-describedby attribute on the See Details link with a value that points to the ID reference of the full travel alert string text. This way the actual details text of the travel alert will serve as the accessible description in the a11y API.

Simple Heading with WAI-ARIA role=heading and aria-level=1

Travel Alert: to me serves as a heading that sections off a chunk of content below it so it needs semantics. I’m fine with not changing the HTML tag here and we can just apply role=heading and aria-level=1 to the <strong> element and BOOM it’s a heading! At least to the screen reader users and the a11y API 🙂

screenshot of VO OS X on the aria heading

VoiceOver reads “heading level 1, Travel Alert:

But can we put role=alert on static text alerts?

So we fixed the missing heading, we fixed the warning icon issue, fixed the link purpose issue… But I had this idea that this really could use even more semantics to help convey its importance because it does not pop up after page load or flash on the screen so there’s no ARIA Live Region because there’s no text being inserted or removed from the DOM.

The Mozilla Developer Network Using the alert role article is the first google result and gave me the idea based on example 1, https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_alert_role.

Example 1: Adding the role in the HTML code

The snippet below shows how the alert role is added directly into the html source code. The moment the element finishes loading the screen reader should be notified of the alert. If the element was already in the original source code when the page loaded, the screen reader will announce the error immediately after announcing the page title.

<h2 role="alert">Your form could not be submitted because of 3 validation errors.</h2>
Now this does not actually work to speak the alert text after the page loads. You MUST use JavaScript to inject a string into a role=alert container that was already present in the DOM on page load for it to actually speak out loud to the screen reader user! So if I removed the string then reinserted it after page load then it would speak, as long as the alert container itself was in the DOM on page load, just not the text. YES IT’S CONFUSING 😉

Results of role=alert on Static Text

So in our travel alert example I add the role=alert attribute/value to the entire alert container and there is NO MAGIC, except if you TAB into the See Details link in which case VoiceOver for OS X will now speak the contents of the alert container which sounds great! Even better because VO OS X does NOT read aria-describedby values by default except after a 7 second delay which is very confusing. This experiment solves that problem and also gives it some logical extra semantics.
TalkBack on Android likes alert roles and speaks the semantics like it’s a heading or some other semantic element.
role=alert on static text does nothing for VoiceOver on iOS but aria-describedby speaks with only a 2 second delay here in Mobile Safari so it sounds great without needing the alert role like OS X VO does.

Live Before & After Demo:


before screenshot

VoiceOver OS X says “visited, link, See Details”.


after screenshot

VoiceOver for OS X says “Travel Alert: Winter Storm Juno, Mid-Atlantic and Northeast United States. See Details, link, alert, visited, link See Details”

VoiceOver OS X “Help Text” or “Hints”:

help tag screenshot

If you wait 7 seconds or so VoiceOver for OS X says the aria-describedby value (also title attributes): “You are currently on a link, inside of HTML content. To click this link, press Control-Option-Space.  The help tag is:  Travel Alert: Winter Storm Juno, Mid-Atlantic and Northeast United States.”

After on Android in Firefox with TalkBack:

firefox android talkback screenshot

TalkBack/Firefox/Android speaks when focused on the After example Travel Alert: heading: “Travel Alert: heading level 1 alert”.

firefox android see details link screenshot

TalkBack speaks when focused on see details link: “See Details – Travel Alert: Winter Storm Juno, Mid-Atlantic and Northeast United States. See Details link”

Include Accessibility in Your Company’s Style Guide – Part 1

It seems that style guides are meant to serve as good examples of Company-Endorsed HTML Code, CSS Usage, Brand Colors, Logo Usage, etc. Their purpose is also likely to train employees in standardized coding practices to make collaboration easier.

So why would your company want to actively promote inaccessible HTML coding methods that actually reduce customer usability of your website and forms?

The Style Guide is the PERFECT place to promote standards-compliant, accessible code and user-centered design/usability best practices!

In Part 1 of this series I’ll post a few inaccessible code examples from Yelp’s style guide which gave me the idea for this topic. 

Examining Style Guides from Web Companies

Stylibrary is a collection of style guides from big web companies like GitHub, Yelp, WordPress, jQuery, and more. Maybe it will be updated with more in the future, I’m sure there are lots of other big company’s style guides out there and I’m sure they have accessibility problems in the code samples. 

Stylibrary | A collection of front end style guides

Yelp recently made their front-end design and development style guide open to the public on their blog, Yelp Product & Engineering Blog: Yelp’s got style (and the guide to back it up). It looked interesting so I checked it out and did my accessibility nerd thing and went straight to examine the code to see if it was actually accessible. 

Styleguide | Yelp

Finding issues like bad color contrast does not surprise me in modern web libraries, e.g. gray on gray text, really light, hard to read gray text, etc. WCAG 2.0 AA color contrast violations are present and can easily be discovered with a contrast analyzing tool like Deque’s FireEyes. 

Forms Accessibility Failures Are More Disappointing

Forms are the first place to look and see if a company is following accessibility requirements. Yelp’s text input examples have label elements that are not connected to their inputs using the for/id construct. Their fieldset examples with radio buttons or checkboxes do not have legends to serve as the common label for the set. 

screenshot showing accessibility errors on labels

Jim Thatcher’s Favlets showing errors on the labels and inputs.

VO reading edit text Placeholder text

Since there is no connected label VoiceOver reads “edit text Placeholder text”.

Yelp’s Inaccessible Form Labels Code

<form class="yform">
<label>Label name</label>
<span class="help-inline">Optional</span>
<input type="text" placeholder="tacos, cheap dinner, Max's">
<label>Label name</label>
<span class="help-block">Optional. Yelper name or an email address.</span>
<textarea placeholder="Placeholder text"></textarea>
<input type="text" disabled="disabled" placeholder="Disabled placeholder text">

Yelp’s Form Labels Code Made Accessible

<form class="yform">
<label for="input1">Label name</label>
<span id="help1" class="help-inline">Optional</span>
<input type="text" id="input1" aria-describedby="help1" placeholder="tacos, cheap dinner, Max's">
<label for="input2">Label name</label>
<span id="help2" class="help-block">Optional. Yelper name or an email address.</span>
<textarea id="input2" aria-describedby="help2" placeholder="Placeholder text"></textarea>
<input type="text" aria-label="Invisible Label Name" disabled="disabled" placeholder="Disabled placeholder text">

In addition to not creating accessible names for a screen reader to speak to a blind user the form labels are also not “clickable”, that is, a mouse user cannot click on the label to put their input cursor into the text field and a mobile user cannot tap on the label to set focus to the input either. This is bad for usability! Our fat fingers need extra space to tap. 

Error Messages Not Programmatically Associated

VO reads edit text blank

Yelp’s form error messages are not spoken by screen readers in forms mode because the error text is not connected to the input. Instead VoiceOver for OS X is shown reading only “edit text blank”. 

Using WAI-ARIA this can be fixed easily like so:

<input type="text" aria-required="true" aria-invalid="true" aria-describedby="error" class="input-error">
<p id="error" class="text-error text-error-inline">Please provide a valid email address</p>

In Part 2 I’m likely going to use GitHub’s style guide for examples because they have TONS of problems with their forms!

Let me know what you think in the comments 🙂