Screen readers, labels and dropdown lists

I’m currently coding a design with no labels just placeholder text.

For input fields like text and email I’m hiding the label with CSS so it is still readable by screenreaders:

<label for="companyName" class="visuallyhidden">Company name</label>
<input type="text" id="companyName" name="companyName"  value="" class="input" placeholder="Company Name *"/>

But I’m not sure what to do with select dropdowns.

Like this?

<label for="favcity"><span class="visuallyhidden">Choose your favourite city?</span>
<select id="favcity" name="select">
<option value="0">Choose your favourite city?</option>
<option value="1">Amsterdam</option>
<option value="2">Buenos Aires</option>
<option value="3">Delhi</option>

Like this?

<label for="favcity">
<select id="favcity" name="select">
<option value="0">Choose your favourite city?</option>
<option value="1">Amsterdam</option>
<option value="2">Buenos Aires</option>
<option value="3">Delhi</option>

This is a handy reference:

Make sure if hiding labels to move them off screen rather than use display: none;.

I put together a form on a page and used Mac VoiceOver to try it out myself:

If you tab through the page then they both work in the same way with the text “Choose your favorite country” being read out

Do you mean when hiding the labels in various ways? I don’t see display: none in your example. Some screen reads do (or used to) ignore elements set to display: none, but I’m not sure which ones.

I used this CSS to visually hide it:

.visuallyhidden {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;

I still want the labels to be read by the visually impaired, the rest will use the placeholder text.

I know that this is frowned upon for making accessible websites ( but I have to deal with the designs as they have been passed on to me

These are what the forms look like in the design:

Ah, they’re using one of the options to display what should be a label : P

(damn I hate smileys, sooo AOL)

I don’t understand why you feel you must wrap your labels in the select section? You don’t with your text inputs. You can do exactly the same technique.

<label for="foo">Hidden foo: </label>
<select id="foo">the select stuff</select>

But there still needs to be ‘choose your favourite city’ as the first response. This what will be used in place of a label.

What about this?

<div class=”favcity-wrapper”>
<label for="favcity" class="visuallyhidden">Choose your favorite city</label>
    <select id="favcity" name="select">
      <option value="0" aria-hidden>Choose your favorite city</option>
      <option value="1">Amsterdam</option>
      <option value="2">Buenos Aires</option>
      <option value="3">Delhi</option>
      <option value="4">Hong Kong</option>
      <option value="5">London</optio>

Here I have added aria-hidden to the first choice to prevent duplication by the screenreader

It seems to me that if the client insists on having one of the options pretend to be a label, then they’d better be totally okay with a user not making a selection at all. value=“0” should be a valid option and if that’s an error, let the back end deal with it. Semantically, you probably agree this is not good use (a choice as a name of the choices who then actually isn’t meant to really be a choice).

I think we web developers want to be really careful with aria-hidden. There’s been a large debate about it, which included debates on whether browsers should be able to detect screen readers or other AT and then whether web developers should have access to that information, and then whether that’s a privacy invasion etc.

The various screen reader makers as well as the browsers have also had long discussions about what to do when there is aria-hidden. In general the concensus seems to be that it should reflect a true state of something on the web page: that it is indeed intended to be hidden, from all users.

So one example of possible good use of aria-hidden is when you’ve made a modal popup and the “rest of the page” part should basically not exist for the user, any user, until the user has either done something within the popup, or closed it. Like when a Javascript alert appears: your only options are within that alert, or closing the alert. But usually sighted people can still actually see the rest of the page. Nowadays a trendy half-opaque dark area is layered over the page, to make the modal stand out, but imagine the modal’s HTML is also outside the whole page element. Some people have taken to using aria-hidden=“true” on the rest of the page part (this only works if the modal is NOT a child of the page), meaning “dearest all users: this page element does not exist. You cannot see it, or interact with it. There is only XUL— er, there is only the modal.”

This should be an acceptable use of aria-hidden because often the rest of the page is unintentionally “visible” (available) to screen reader users, and in a modal situation, there should only be the modal. Aria-hidden is a special way to tell AT (and browsers) “this element is meant to be hidden from all users.”

AT writers and browser vendors also have to deal with, what if the author (you) put aria-hidden on something and inside are focusable children (or on focusable thingies? like options?)? Some browsers and AT will scour the entire tree at every change of events to check if now someone has an aria-hidden state, and then if so if any focusabled are descendents, blah blah. They may ignore aria-hidden on something that is otherwise normally within the default tab order, figuring you’ve made a mistake as an author.
For these reasons I’m really careful with aria-hidden. Anything you have hidden anyway, like display: none stuff, input type=“hidden”, etc, could reasonably have aria-hidden added as an extra hint to state to AT.

When trying to reduce verbosity, it starts getting a bit more muddled as to whether this is a good thing: should we have AT users seeing a different version of the page than sighted ones? Now since basically you have two versions of a label (a real label and an option being used as a label), you could argue that you are actually still showing one version of things to all users. But I think there can be a better way. Unless you’re always going to manually move the focus to the first “real” option whenever a user focusses on the select? You shouldn’t be able to focus on something that’s hidden.

Especially if the back end will be configured to reject the first option as a valid one, you could try using it as a label for both the sighted and the AT users.

<option value="0" id="fake_label">Choose your favorite city</option>```
 It is legal to let children label parents. aria-labelledby will override any outside labels, so you could keep that other label for older browsers/AT, but newer ones would ignore the real label. You still have the weirdness that this is actually an option. That is its default role and it has option behaviours built-in the browser and all that.

Another option is to do some fancy CSS and Javascript where the label is visible and covering the select, until users have both focussed on the select *and* made a change so something other than the first item is selected.  The first item, if truly allowed as an option, would really say "no preference".
```<div class=”favcity-wrapper”> <-- position: relative
<label for="favcity">Choose your favorite city</label><-- position: absolute, Javascript listens
<select id="favcity" name="select">
      <option value="0" aria-label="no preference"> </option>```
This does sound like a lot of work that might be silly though, but we've seen it done on regular text inputs, where the label is mimicking a placeholder. At least the above, while being more convoluted, lets us keep sanity with the semantics of the HTML. The option can now act like what it is, an option. The label can be a label. AT and non-AT users are honestly seeing, and interacting with, the same thing. 

It's more honest, in my opinion, but it's also more work, esp. styling form controls cross-browser can be a b*tch. But otherwise I'd still rather let the controls be a bit more verbose than try aria-hidden on a focusable thingie.
You might already have extra verbosity if there's a legend, which sometimes annoyingly gets announced before every control inside the fieldset. Or the user might have ZoomText, which in IE for some reason not only reads out all titles, but with radio buttons and checkboxes, the values of the controls are read out. So often these users get to hear a lot of nonsense along with the labels (and you can't help this, it's some kind of ZT bug and it doesn't happen in Firefox).

You know, I ought to just try to code one of these up. It’s all well and good to say “THOU SHALT USE SEMANTIC ELEMENTS” but it’s nicer to also be given an implementation of something, if it’s complicated. I always appreciate things like a complicated slider demo because figuring it out myself is often not an option for a deadline.

It might be too late for your case, Cotton, but I just ran across a terrible jQuery implementation being used in an iframe popup by a client of ours. I totally think I can do better (but, probably not styled as well cross-browser so much, which is prolly why they used this jQuery thing).

Yes, examples are great—and preferably simple ones that con’t include too much. For example, I’d love to see a simple demo of ARIA roles on a lightbox done properly. You read so much on ARIA, but by the end of it your eyes are spinning and it all seems too hard.

Thanks for that info on aria-hidden Stomme. I actually wrote a blog article on styling HTML select and checkboxes (!/blog/141056/using-css-style-notoriously-tricky-form-elements-checkboxes-select-dropdowns) using that code. I’ll make an amendment with a link to your contribution above.

I do wonder whether in years to come we’ll look at ARIA as a failed project. At one time it was common to see websites offering an accessible-friendly version of their website, which usually meant just text and images, but then accessibility advocates pushed for one website for all, so that practice went out of the window.

ARIA is complicated and is interpreted by browsers and screen readers in different ways. The intentions behind ARIA are noble, but the execution is lousy.

I was at the Wordpress Euro conference in Amsterdam last Autumn and I ended up talking to Bram Duvigneau over lunch (I think he’s somebody you might personally know Stommes) and he was totally dismissive about using ARIA, which surprised me. (Bram is a blind developer with a very friendly labrador, for those don’t know)

Arg, your final result is unclickable in Opera! I can guess it’s maybe because Opera (my version) agrees that pointer-events do exist (so something like modernizr would think it’s supported), but doesn’t actually do anything with them. Worse than IE9 there.
I only know this because Lea Verou mentioned it in a CSS talk where, for the first time, I heard of wonderful pointer events, which I use in code all the time to disable clickables who don’t actually have a disabled property, or do but then I can’t style it.

I have used something similar to your technique for fancy checkboxes and radios. I had to make kinda big sprites for these, for focused-but-unchecked, focused-and-checked, disabled.

I think it was based on cssninja’s implementation, and does suffer the zoom issue (blurring, which yours should not as you use SVG).
My implementation used a container around each label-input pair, and IE didn’t like, so I had to make certain IE8 didn’t get all my padding and positioning and stuff.


Originally, the creators hoped it would die eventually, the way the PhoneGap people hope some day their software no longer gets used (…because not-needed). HTML5 specs have added many roles and states to HTML elements, meaning they are the same as those in ARIA.

However as we know, HTML is limited, and HTML5 cannot replace ARIA. It simply doesn’t cover every case and tends to leave us with little more than divs and spans and anchors to create complex applications or widgets. This is where ARIA is most necessary because basically, you’re making a new thingie and need a way to tell the underlying OS what these are and what they should do. Each OS has a list of controls, states, permitted behaviours/listeners and whatnot on things. For example, the reason a browser knows what a checkbox is isn’t because of HTML (I should say, not only because of HTML), but because the Operating System knows what a checkbox is (and so therefore the browser, other desktop applications, etc).

This is why when a screen reader user is using a browser to access a web page with a checkbox, that underlying accessibility layer of the OS is able to tell the SR “this is a checkbox, and its state is checked|unchecked”.
Here is a better and deeper explanation.

I see the execution of it as being no more or less finicky than any other browser/OS-implemented thingies. Few things work completely the same cross-everything. Watch:

Yes, I know Bram, met him and Abbott twice, I think. Have you ever met a non-friendly labrador?

I haven’t talked with Bram about ARIA, but it wouldn’t surprise me if his beef with it is when it’s used as a substitute for regular semantic HTML (like when Google pulls this shit: <span role="link">click me!</span>+a pile of onclick listeners), or when developers make something like a menu* or other quite complicated widget but don’t follow the spec entirely. Screwing up one role or state or not following the rules of which elements with roles can contain which other roles, etc, will break compliant browsers and readers. Another known issue is developers using application roles on things because the name suggests “put this on whatever you think is an application” without understanding that an application role means “hijack the built-in AT keyboard functions so the developer can replace them with his/her own listeners”. Which for things some people might consider applications (a modal dialog with a form in it) shouldn’t have this role as it prevents simple things like reading text or navigating.

On the flipside, without ARIA, complex weirdo widgets would not be usable, and unfortunately there are code writers like Google who for whatever reason choose to write terrible shitty HTML and then patch it up with ARIA, which means that they are not using best practices but more users can actually use their products (though Google is a special case, because they keep building everything to only work with their screen reader, ChromeVox. ChromeVox is a javascripted thingie that so far as I know does not talk to the underlying OS accessibility layer, and thus does not entirely act like a real screen reader).
I mean, how exactly do you code up drag and drop? How do you let a user know that they have selected a thingie and that it can be dragged, or that it has been successfully dragged to a receptive receiver? There is no native equivalent, and even after javascripting all the behaviour, it’s difficult. Oh yeah, and the arrow keys for dragging the thing… might already be in use to read-by-word or read-by-character in the AT. Thus, for now, ARIA.

But, the point of trying native/semantic first (good practice, like mobile-first or content-first), It’s why as a developer I’d probably try to spend the time seeing how I could keep the label being a label and the first option being an option in your dilemma first. (or multilemma? since there are multiple ways of doing this)

* re menu: here I don’t mean a navigation menu, although people seem to be ARIA-ing these up as menus. By “menu” I mean like the menu you get when you right-click somewhere. An application menu. These need some special ARIA junk on them to fully reflect what they’re doing, or no ARIA at all, but adding some or adding it incorrectly will completely break it for someone. I wish the specs were clear on what “menu” means, despite the fact that it only talks about “controls” inside them etc.

1 Like