"Slick UX"



"Slick UX"

0 1


accessibility-of-mvcs

Slides and demos for presentations on the Accessibility of Single-Page Apps

On Github marcysutton / accessibility-of-mvcs

"Slick UX"

Pause video halfway through to explain mouse vs. screen reader interaction

What is Accessibility?

Everyone can perceive, understand, navigate, and interact with the Web, and they can contribute to the Web.

W3C definition

Millions of people have disabilities that affect their use of the Web.

Web accessibility also benefits people without disabilities.

Refer to slide #2 about the kinds of apps we build.

80 million Europeans with disabilities

Source: European Disability Forum

15% of the European population

Source: European Disability Forum

Accessibility is about

PEOPLE.

JavaScript for Everybody

Accessibility of JavaScript MVCs

Created by Marcy Sutton / @marcysutton

Best framework?

ModelViewControllerRouter*WHATEVER

Characteristics of single page, client-rendered apps: MV*W code patterns; async;

Are your apps accessible?

It could depend on:

  • The framework*
  • Screen reader
  • Browser
  • Your code*
* Things you can control, to varying degrees
You can submit PRs to frameworks, refine your code, even petition browsers. Can't do as much about screen readers.

#a11y in single-page apps

  • Manage ARIA attributes
  • Enable the keyboard
  • Handle focus
  • Write meaningful HTML
  • Alert the user
Handling focus: tabIndex, replacing part of the DOM causes focus mgmt probz *Graceful degradation is worth mentioning but it is outside the scope of this talk.

Accessible Rich Internet Applications

Expands HTML's semantic vocabulary

ARIA Core Components 1 of 3

Roles

What does this thing do?

      <div role="img" style="background-image..."></div>
            

ARIA Core Components 2 of 3

States

The current condition of this particular thing

    <material-input aria-disabled="true"></material-input>
            
Explain redundancy: an aria-disabled attribute versus a regular disabled attribute: the latter only works on certain elements. For custom components, this extends the vocabulary. Try keying off of the ARIA attribute or make the framework inject ARIA keying off 'disabled'

ARIA Core Components 3 of 3

Properties

The nature of the current object

     <doner-kebab aria-label="Lunch courtesy AngelinaMagnum">
            

Using Roles

  • They're element types
  • They're landmarks
  • Start with native HTML tags
  • Read the documentation
  • Don't overdo it
Simplest abstraction possible

Application Role

Disables a screen reader’s “virtual cursor”

       <sparkle-party role="application"></sparkle-party>
						

Marco Zehe's post about using Application Mode

Virtual Cursor/Browse mode: Several keys are captured by the assistive technology and are not processed by the browser. These allow navigation by headings, lists, links, tables, form elements and others. Usually, these are done via single letters. The visual focus may or may not follow the virtual cursor onto focusable items, depending on the assistive technology in use and its settings

Forms mode/focus mode: All keys are passed through to the browser. The challenge is that you may be creating widgets that require you to force the user into direct interaction with the browser. You know that your widget can best be used via the keyboard if the user is not in virtual mode. It is under your control whether the user is being thrown into focus mode once your widget gains keyboard focus.

Don't Do This

         <body role="application">
            
Only want to use role="application" if the content you're providing consists of only interactive controls, and of those, mostly advanced widgets, that emulate a real desktop application.

Document or Application?

  <sparkle-party>
    <h2>Do you like to dance?</h2>
    <button class="lets-dance">I wore my party pants</button>

    <disco-ball>
      <canvas></canvas>
      <p aria-live="polite" class="disco-transcript"></p>
    </disco-ball>
  </sparkle-party>
					
Client-side apps often blur the lines between application and document. Because accessibility works best with a document structure, it's best to selectively use the application role on a per-widget basis. Care must also be taken for the correct roles, states and properties for non-native elements or interactions.

Enabling the keyboard

Challenge the concept of "interactive". It doesn't have to be visually interactive. Appeal to all the senses. PERCEIVABLE and OPERABLE. And robust. And understandable.

Tab Index

<div tabIndex="0"></div>

What Not To Do

        <div class="menu" ng-click="toggleMenu()"></div>
          
Hamburger button is a div with no tabIndex, role or keypress event

Close, but no keypress.

  <dance-button tabIndex="0"
    ng-click="spicy123(go);">
    DANCE!
  </dance-button>
						
DANCE!
Rest

Everybody dance!

  <dance-button tabIndex="0" role="button"
    ng-click="letsGetDown(toThat)"
    ng-keypress="letsGetDown(toThat)">
    DANCE!
  </dance-button>
						
DANCE!
Rest
Loading beat data...
You can test for a11y by mocking & expecting keyboard events, could be hooked up to continuous integration process

Keyboard Accessibility

One Simple Trick

  [tabIndex="0"] {
    color: $linkColor;

    &:focus, &:hover {
      color: $linkActiveColor;
      outline: default;
    }
  }
					

Tom Dale, Co-Creator of Ember.js and Wearer of Party Pants

Photo by Matthew Bergman

Ember Custom Component demo

Custom Elements

Ember.js

    {{party-pants}}
					
    App.PartyPantsComponent = Ember.Component.extend({
      tagName: 'party-pants',
      ariaRole: 'article',
      attributeBindings: ['tabIndex'],
      tabIndex: function() {
        return this.get('active') ? 0 : -1;
      }.property('active')
    });
					

Make your framework do the heavy lifting 1 of 3

  // AngularUI Bootstrap
  <accordion-group
    is-open="status.open"
    is-disabled="status.isDisabled">
  </accordion-group>


          

Make your framework do the heavy lifting 2 of 3

  // AngularUI Bootstrap
  <accordion-group
    aria-expanded="true"
    is-open="status.open"
    aria-disabled="false"
    is-disabled="status.isDisabled">
  </accordion-group>
          
Angular properties alongside aria properties get verbose.

Make your framework do the heavy lifting 3 of 3

Example where ARIA attributes are the default

  // AngularUI Bootstrap
  <accordion-group
    ng-expanded="status.open"
    ng-disabled="status.isDisabled">
  </accordion-group>


          

Angular.js Material Design

Here's how I practice what I preach

Angular Material Radio Buttons

<material-radio-group ng-model="data.group">
  <material-radio-button value="1">
    Label 1
  </material-radio-button>
  <material-radio-button value="2">
    Label 2
  </material-radio-button>
</material-radio-group>
					

Angular Material Radio Buttons (cont'd)

function materialRadioGroupDirective() {
  element.attr({
    'role': 'radiogroup',
    'tabIndex': '0'
  })
  .on('keydown', keydownListener);

  function keydownListener(ev) {
    if (ev.which === Constant.KEY_CODE.LEFT_ARROW) {
      rgCtrl.selectPrevious(element);
    }
    else if (ev.which === Constant.KEY_CODE.RIGHT_ARROW) {
      rgCtrl.selectNext(element);
    }
  }
}
function materialRadioButtonDirective($expectAria) {
  element.attr('role', 'radio');
  $expectAria(element, 'aria-label', element.text());

  var lastChecked;
  attr.observe('value', render);
  function render() {
    var checked = (rgCtrl.getViewValue() === attr.value);
    if(checked === lastChecked){ return; }
    lastChecked = checked;
    element.attr('aria-checked', checked);
  }
}
					

Make it sparkle.

Play German Sparkle Party Video

Thanks, JSConf EU! -@marcysutton

Accessibility of JavaScript MVCs@marcysutton / MarcySutton.com