Many times ARIA is used as a quick fix for accessibility issues caused when more semantic elements should have been used. For instance, an input could use aria-label when the design for the page does not include a visible label tag. Another common use is role="button" when links are used for actions instead of the semantic button. ARIA roles and attributes provide simple solutions to low-hanging fruit; something developers with legacy code and screen reader users can appreciate.
This post, however, will show how ARIA can make a dynamic form more responsive to a user. We have a contact input form for the user to add an email address type and value. We're going to use ARIA and JavaScript to give that text input a type-specific label by grabbing the information from the option previously selected. It's actually quite simple and ingenious.
Use aria-labelledby to reference the input's label
Normally a form input is referenced by a label.
<input type="search" name="search" id="search">
The aria-labelledby attribute lets the input reference another element on the page as its label. This allows everything from headers, paragraphs, and other form elements to act as a label for the input. The following example uses a module's h3 header as the label for a search input.
<input type="search" name="search" aria-labelledby="search-header">
Creating the dynamic labels
In our example, Dynamic form label with ARIA, there is a select list for the email type and an input for the address. The first option has an id that is referenced by the text input's aria-labelledby attribute. As the user selects an option it is given an id and the email input receives this new id in the aria-labelledby attribute. The following video shows the interaction of the select and text inputs. The HTML:<label for="email-opts">
Email:
</label>
<select id="email-opts" name="email-opts">
<option id="email-opts-work" value="WORK">Work Email</option>
<option value="PERSONAL">Home Email</option>
<option value="Family" >Family Email</option>
<option value="Secret">Secret Email</option>
</select>
<input aria-labelledby="email-opts-work" type="text" name="email" value="">
</form>
<label for="email-opts">
Email:
</label>
<select id="email-opts" name="email-opts">
<option id="email-opts-work" value="WORK">Work Email</option>
<option value="PERSONAL">Home Email</option>
<option value="Family" id="yui_3_3_0_1_131361980471217">Family Email</option>
<option value="Secret">Secret Email</option>
</select>
<input type="text" value="" name="email" aria-labelledby="yui_3_3_0_1_131361980471217">
</form>
The JavaScript solution
This form uses the Yahoo! User Interface (YUI) library to simplify this solution. YUI solves browser inconsistencies and provides built in functions for selecting DOM nodes, adding IDs, as well as changing attributes. The script starts by calling the base YUI 3.4 script. We then request the "node" and "event" functionality. The setLabel function generates an id on the selected option and then sets that value on the input's aria-labelledby attribute. The script also looks for an input with aria-labelledby and then associates it with the select item that precedes it. It then calls the setLabel function whenever an option is chosen.<script type="text/javascript" charset="utf-8">
YUI().use("node", "event", function (Y) {
function setLabel(input, select) {
input.set("aria-labelledby", select.all("option").item(select.get("selectedIndex")).generateID());
}
Y.all("input").each(function (input) {
var select;
if ((select = Y.one("#" + input.get("aria-labelledby")).ancestor("select"))) {
select.on("change", function () {
setLabel(input, select);
});
}
});
});
</script>
JQuery variation
You can also use jQuery, although it will require a few modifications to the form.- Add an id to each of the options in the select (as jQuery doesn't have the cool generateID method)
- Add a class "labelledbyselect" to the element that should be labelled to add flexibility (it can now also be any form input type i.e. a textarea)
<label for="email-opts">
Email:
</label>
<select id="email-opts" name="email-opts">
<option id="email-opts-work" value="WORK">Work Email</option>
<option id="email-opts-personal" value="PERSONAL">Home Email</option>
<option id="email-opts-family" value="Family">Family Email</option>
<option id="email-opts-secret" selected="selected" value="Secret">Secret Email</option>
</select>
<input class="labelledbyselect" aria-labelledby="email-opts-work" name="email" type="text">
</form>
</script>
<script type="text/javascript" charset="utf-8">
jQuery(function($) {
$('.labelledbyselect').each(function() {
var labelled = $(this),
select = $('#' + labelled.attr("aria-labelledby")).parent('select');
if (select.size()) {
select.change(function() {
labelled.attr('aria-labelledby', select.find('option:selected').attr('id'));
});
}
});
});
</script>