Making Accessible Ember Components

I’m Josh

I work at Uniiverse

@jdjkelly &&

What are components?

Web Components

Templates, Custom elements, Imports, Shadow DOM

Ember Components

Templates/Layouts, Ember.Component, Resolver, ???

An Ember.Component might look like this:

App.NameTagComponent = Ember.Component.extend({
    actions: {
        hello: function(name) {

Its template might look like this:

<div {{action 'hello'}}>
    Hi, my name is {{}}

It might be instantiated like this:

{{name-tag person=current_user}}

What is accessibility?

“Screen readers don’t work with Javascript”

Wrong, wrong, wrong. Screen readers only care about DOM.



Accessible Rich Internet Applications

Sounds like Ember, right?


Accessible elements

Roles & States/Properties


allows the author to annotate host languages with machine-extractable semantic information about the purpose of an element

Or: the purpose of an element in the DOM

Simplest possible example:

<div role="button">
   Click me


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


combobox grid listbox menu menubar radiogroup tablist tree treegrid

An example of a component with parent and child roles is a menu:

<awesome-nav role="menu">
   <div role="menuitem">Item one</div>
   <div role="menuitem">Item two</div>


What meaningful properties does this object have at this time?

<awesome-nav role="menu" aria-expanded="true">
   <div role="menuitem">Item one</div>
   <div role="menuitem">Item two</div>

Roles communicate the purpose of the component to the assistive software.

States communicate the state of the current state of the component.

Applying ARIA to Ember

Role support is built-in

Taco Button Component example


App.TacoButtonComponent = Ember.Component.extend({
  tagName: 'taco-button',
  nameBinding: '',
  attributeBindings: ['label:aria-label', 'tabindex'],
  answer: false,

  label: function() {
    return "Are " + this.get('name') + " tacos tasty?";

  tabindex: -1,
  ariaRole: 'button',

  click: function(event) {

  keyDown: function(event) {
    if (event.keyCode == 13 || event.keyCode == 32) {;




{{taco-button taco=model}}

Rendered DOM

<taco-button aria-label="Are spicy tacos tasty?" tabindex="1" role="button">
    Are spicy tacos tasty?

What about something more complex?

Buffer slide

  • A note about future proofing
  • What’s the shadow DOM?
  • Is the Shadow DOM keyboard navigable?
  • So when Ember Components implement Shadow DOM will they still be accessible?


Come see an expanded version of this talk at Toronto Javascript on June 23

notes && slides