Making Accessible Ember Components
====================
Making the web accessible is important. We have ethical and, in some cases, legal obligations to ensuring access to all of users.
Luckily for us, it's easy to make an accessible Ember Component.
## What are components?
To understand the accessibility story around Ember Components, we have to start by talking about *Web* Components. Ember Components are designed to be interoperable with the final Web Components API.
Web Components | Ember Components
--------------------- |-------------
Templates | Templates
Custom elements | Ember.Component
Imports | Resolver
Shadow DOM | ???
An Ember.Component might look like this:
App.NameTagComponent = Ember.Component.extend({
tagName: 'name-tag',
actions: {
hello: function(name) {
alert(name);
}
}
});
This is a simple button. It has an action that pops open an alert that displays the string it's passed as the arg `name`. Its template might look like this:
Hi, my name is {{person.name}}
It might be instantiated like this:
{{name-tag person=model}}
Here's a demo: [JSBin](http://emberjs.jsbin.com/pebep/1/edit)
We don't need to worry about how the Resolver works - that's an implementation detail solved by the framework. But keep the Shadow DOM in mind - I'll mention it under `Future Proofing`.
## What is accessibility?
The ability to use an application. When a user has diminished control over an input device (keyboard, mouse), assitive technologies fill the gap. Screen readers are an extremely common example.
If you're using OS X you've got a screen reader built into your operating system. It can be opened by hitting `⌘-F5`.
The W3C maintains a number of accessibility specs. The most important of these, for the Ember developer, is **WAI-ARIA** - or Web Accessibility Initiative - Accessible Rich Internet Applications.
### ARIA Architecture
At a high level, the ARIA API is a way of annotating HTML to define the behaviour of an arbitary element. This diagram from the accessibility gives us a good idea of how ARIA fits into what we're building.

So it turns out - and this might surprise some experienced developers - that Javascript ain't no thing for screen readers - as long as that Javascript is building DOM. Which is exactly what Ember does (this will be truer still with HTMLBars).
ARIA gives us two primitives to mark up our HTML with: Roles and States/Properties. In using both in combination we can produce DOM that is semantically meaningful to a screen reader.
#### Roles
> The role attribute, borrowed from the, Role Attribute [ROLE], allows the author to annotate host languages with machine-extractable semantic information about the purpose of an element. It is targeted for accessibility, device adaptation, server-side processing, and complex data description.
Put another way, a role is the purpose of an element in the DOM.
Simplest possible example:
Click me
ARIA gives us *lots* of roles to work with. The most basic roles can "act as standalone user interface widgets or as part of larger, composite widgets":
alert alertdialog button checkbox dialog gridcell link log marquee menuitem menuitemcheckbox
menuitemradio option progressbar radio scrollbar slider spinbutton status tab tabpanel
textbox timer tooltip treeitem
We also have access to complex roles, with child-role relationships:
combobox grid listbox menu menubar radiogroup tablist tree treegrid
An example of a component with parent and child roles is a menu:
Item one
Item two
#### States and Properties
> What meaningful properties does this object have at this time?
We also need a way to be able to describe various properties and states a component might have.
Item one
Item two
When a user tabs to the `awesome-nav` element, we need to be able to communicate the state of the menu to the screen reader. Otherwise, there would be no way to determine if the next tab action should highlight or move on to a sibling element.
It should be obvious that the element's role will dictate which states/properties are relevant. These states/properties can be required, supported, or inherited. For our purposes this distinction isn't important. All we need to know right now is that a given role has a given list of states/properties which can be meaningful.
The `menu` role, for example, allows use to specifiy any of the following states/properties:
aria-activedescendant aria-atomic aria-busy aria-controls aria-describedby aria-disabled aria-dropeffect aria-expanded aria-flowto aria-grabbed aria-haspopup aria-hidden aria-invalid aria-label aria-labelledby aria-live aria-owns aria-relevant
### Summary
Roles communicate the purpose of the component to the assistive software.
States communicate the state of the current state of the component.
## Accessible Ember Component Examples
### Built-in support?
Ember.Component - by way of Ember.View - actually gives us built-in support for a property called ariaRole. We can pass this property a string, and it will automatically fill in the `role` attribute in the generated DOM. Otherwise, we need to do a little bit of work ourselves.
### Button Example
#### taco-button.js
App.TacoButtonComponent = Ember.Component.extend({
tagName: 'taco-button',
nameBinding: 'taco.name',
attributeBindings: ['label:aria-label', 'tabindex'],
answer: false,
label: function() {
return "Are " + this.get('name') + " tacos tasty?";
}.property('name'),
tabindex: -1,
ariaRole: 'button',
click: function(event) {
alert('Yes');
},
keyDown: function(event) {
if (event.keyCode == 13 || event.keyCode == 32) {
this.click(event);
}
}
});
Parts worth mentioning: tabindex, ariaRole, aria-label, keyDown
**tabindex**: makes the content accessible via tabbing
**ariaRole**: outputs a role attribute to the DOM
**aria-label**: can be semantically important (for our demo this won't matter)
**keyDown**: captures enter/space keyboard presses which emaulate the behaviour of a click
#### components/taco-button.hbs
{{label}}
#### index.hbs
{{taco-button taco=model}}
#### Rendered DOM
*Note: I've omitted the metamorphs and ember-view ID attributes*
Are spicy tacos tasty?
[JS Demo: Accessible Example](http://emberjs.jsbin.com/jidawave/2/edit)
[JS Demo: Inaccessible Example](http://emberjs.jsbin.com/jidawave/3/edit)
Pop open VoiceOver and check out the difference for yourself.
### Menu Example
[ic-menu](https://github.com/instructure/ic-menu)
## A note about future proofing
Recalling the difference between Web Components and Ember Components:
Web Components | Ember Components
--------------------- |-------------
Templates | Templates
Custom elements | Ember.Component
Imports | Resolver
Shadow DOM | ???
### What's the Shadow DOM?
> [T]here is a fundamental problem that makes widgets built out of HTML and JavaScript hard to use: The DOM tree inside a widget isn’t encapsulated from the rest of the page. This lack of encapsulation means your document stylesheet might accidentally apply to parts inside the widget; your JavaScript might accidentally modify parts inside the widget; your IDs might overlap with IDs inside the widget; and so on. **Shadow DOM addresses the DOM tree encapsulation problem.**
[HTML5 Rocks](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
### Is the Shadow DOM keyboard navigable?
"Yes"
-[Marcy Sutton](http://substantial.com/blog/2014/02/05/accessibility-and-the-shadow-dom/)
### So when Ember Components implement Shadow DOM will they still be accessible?
Yes.
## Call for help
If all this sounds great, please send a PR adding accessibility to the Ember UI project. I've added support for a few in my free time. It would be great to see other people at this meetup contribute.
## Thanks!
Come see an expanded version of this talk at [Toronto Javascript on June 23](
http://www.meetup.com/torontojs/events/190285612/)