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 🙂

Image & Text Inside a Link Accessibility Issues (Alt & Title Attribute, Expanded/Collapsed State, WAI-ARIA aria-expanded)

This blog post in inspired by the problem where developers have expandable/collapsable content usually in the form of a list of FAQ questions. The question has a +/- graphic that visually indicates to the user to click to expand and see the answer to each FAQ question.

Expanded/Collapsed State

So the accessibility problem is how do you indicate expanding/collapsing content to screen readers?

Another issues sometimes seen is that the developer will have two separate links, the image and the text. These should be combined into one link element for simplicity and to increase the click target area.

Options to Indicate Expanded/Collapsed State

Alt text on the image.
Title attribute on the link, null alt on image.
WAI-ARIA’s aria-expanded on link, null alt.
Visually hidden state text.

Alt on Image

My first thought is alt on the image that dynamically changes from expanded to collapsed using JavaScript. This would be the accessibility standards way of coding it.

Title on Link

Lots of folks like to use the title attribute to indicate things that are not visible in text. I think the title attribute is best used for screen magnification accessibility and possibly cognitive usability improvements. I don’t think the title attribute should be relied upon to communicate information. You’ll see one reason in the test cases.


Personally I love WAI-ARIA and would love to use it for everything. Indicating state with aria-expanded is another accessibility standards way of doing things. The only problem is browser/AT support.

Visually Hidden Text

And then of course there’s the good old trusty visually hidden text positioned with CSS off the screen so that the text is physically there, just not visible to sighted folks unless they disable CSS. The great thing about visually hidden text is that it behaves the same in all browsers and AT. It’s always read no matter what and read in the order you place it.

Test Cases (external link) Inline Below

Alt on image

ExpandedHello World

AT Behavior

VO reads link Expanded Hello World

  • VoiceOver OSX 10.8.1 – Alt read then link text.
  • NVDA 2012.2.1 – Alt read then link text.
  • JAWS 13.0.924 – Alt read then link text.
  • VoiceOver iOS 5.1.1 – Only link text read, NO alt.

Null alt on image, title on link

Hello World

AT Behavior

VO reads link Hello World
VO reads You are currently on a link, inside of a HTML content. To click this link, press Control-Option-Space. The help tag is: Expanded

  • VoiceOver OSX 10.8.1 – Link text then title is only read as the help tag after a 7 second delay or pressing control+option+shift+h to read help tag (title) manually. User will not know if a help tag is present unless they wait for the 7 second delay or press the help tag command.
  • NVDA 2012.2.1 – Link text then title (in Firefox). Link text, NO title (in IE).
  • JAWS 13.0.924 – Link text then title (in Firefox). Link text, NO title (in IE).
  • VoiceOver iOS 5.1.1 – Only link text read, NO title.

Null alt on image, aria-expanded on link

Hello World

AT Behavior

VO reads expanded link Hello World

  • VoiceOver OSX 10.8.1 – aria-expanded then link text.
  • NVDA 2012.2.1 – Link text then aria-expanded.
  • JAWS 13.0.924 – Link text, NO aria-expanded.
  • VoiceOver iOS 5.1.1 – Only link text read, NO aria-expanded.

Null alt on image, visually hidden state text

Hello World

AT Behavior

VO reads link Hello World Expanded

There is no difference. Visually hidden text is always read in the order it is placed.

Thoughts on Results

The results are not encouraging. I was going to suggest using either alt on the image or visually hidden text but after testing on VoiceOver iOS 5.1.1 alt on an image is not read. You can say that this is all due to browser and AT bugs because the accessibility coding is correct.

Bulletproof Accessibility

The only bulletproof method is using visually hidden text to indicate state and placing that state text in whatever order you choose it to read. I placed the visually hidden state text after the link text in my test case. The decision comes down to what browsers and AT you support and if you want to work around screen reader/browser bugs to provide a more usable solution or if you chose to follow accessibility standards and wait for the AT/browsers to fix themselves.

Your Thoughts?

Hope this helps! Please let me know if you have any questions or feedback.

I will retest this with iOS 6 GM once I get it installed on my iPhone. I think it handles the title attribute differently with a 2 second delay instead of 7 on OS X.