Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ThomasBurleson
Forked from marcysutton/developer-guide.md
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThomasBurleson/d98ac72ee4465dca873f to your computer and use it in GitHub Desktop.
Save ThomasBurleson/d98ac72ee4465dca873f to your computer and use it in GitHub Desktop.

##Introducing ngAria

A new feature released in Angular 1.3.0 is the accessibility module: ngAria. As someone involved in with the development of this community-driven module, I thought it might be helpful to introduce ngAria. I'll also explain what the module can’t do and what issues you must consider when building accessible, single-page web applications with AngularJS.

The goal of ngAria is to improve Angular's default accessibility by enabling common ARIA attributes for directives. Using ngAria is as simple as requiring the ngAria module in your application. ngAria hooks silently hooks into standard AngularJS directives and quietly injects accessibility support into your application at runtime.

The list of supported directive attributes is currently limited; but we are identifying other ways the module can improve accessibility by default. To explain the current state of the module, I’ll go through each directive that uses ngAria:

Now let's review each of the AngularJS directives that are enhanced with accessibility features by ngAria:


####ngDisabled

Since the disabled attribute is only valid for certain elements such as button, input and textarea. Now let's consider custom elements such as <md-checkbox>, <md-tabs>, etc. These types of custom elements are not native input elements. To ensure a custom element becomes properly disabled, developers toggle the element with ngDisabled.

Additionally, ngAria for ngDisabled tells assistive technologies when the custom control is disabled and injects the aria-disabled attribute and value into the DOM element. To see how this is performed with ngAria, let's review a code snippet:

ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
  return $aria.$$watchExpr('ngDisabled', 'aria-disabled');
}])

Shown above, we see that the ngAria module creates a directive with the same signature as the traditional ng-disabled directive. But this ngAria version (of ngDisabled) is dedicated to solely managing accessibility attributes. An internal service $aria is used to watch the boolean attribute ngDisabled. If aria-disabled has not been explicitly set by the developer, then aria-disabled is injected as an attribute with its value synchronized to the value in ngDisabled.

And - best of all - since the ngAria functionality hooks into the ng-disabled directive, developers do not have to do anything to enable this feature. The aria-disabled attribute is automatically managed simply as a silent side-affect of using ng-disabled (with the ngAria module required).

You can check whether a control is legitimately disabled for a screen reader by visiting chrome://accessibility.

####ngModel

Most of ngAria's heavy lifting happens in the ngModel directive. For elements using ngModel, special attention is delivered by ngAria if that element also has a a role or type of checkbox, radio, range or textbox.

ngAria will dynamically bind and update the following ARIA attributes (if they have not been explicitly specified by the developer):

  • aria-checked,
  • aria-valuemin,
  • aria-valuemax,
  • aria-valuenow,
  • aria-invalid, and
  • aria-required

ngAria will also manage that element's tabIndex attribute to ensure that each custom elements with these roles will be accessible from the keyboard.

Note that it is still up to you as a developer to ensure custom controls will be operable from the keybard.

Think of ng-click on a <div> or <md-checkbox>: you still need to bind ng-keypress to make it fully operable. As a rule, any time you create a widget involving user interaction, be sure to test it with your keyboard and at least one mobile and desktop screen reader (preferably more).

####ngShow

The ngShow directive shows the given HTML element based on the expression provided to the ngShow attribute.

The element is shown by removing or adding the .ng-hide CSS class onto the element. In its default setup, ngAria for ngShow is actually redundant. It toggles aria-hidden on the directive when it is hidden or shown. However, with the default CSS of display: none !important, child elements will already be hidden from a screen reader.

Where aria-hidden becomes useful is when the default CSS is overridden with properties that don’t affect assistive technologies, such as opacity or transform. By toggling aria-hidden dynamically with ngAria, we can ensure content visually hidden with this technique will not be read aloud in a screen reader.

One caveat with this combination of CSS and aria-hidden: you must also remove links and other interactive child elements from the tab order using tabIndex=“-1”. This ensures screen reader users won't accidentally focus on "mystery controls". Managing tab index on every child control can be complex and affect performance, so it’s best to just stick with the default display: none CSS...making aria-hidden unnecessary. See the fourth rule of ARIA use.

####ngHide

The ngHide directive hides the given HTML element based on the expression provided to the ngHide attribute.

The element is hidden by adding the .ng-hide CSS class onto the element. In its default setup, ngAria for ngHide is actually redundant. It toggles aria-hidden on the directive when it is hidden or shown.

####ngClick and ngDblClick If ngClick or ngDblClick is encountered, ngAria will add tabIndex if it isn't there already. Even with this, you must currently still add ng-keypress to non-interactive elements such as <div> or <taco-button> to enable keyboard access. I have recommended this also bind ng-keypress to be the most useful; the conversation is currently ongoing.


##Proposed for ngAria or Elsewhere

###ngMessages

I have an ngAria pull request open for ngMessages, an error messaging module, that will cause the errors to be read aloud in a screen reader as they become visible. This was easily accomplished by adding aria-live, an ARIA messaging mechanism, to any element using ng-messages. It was a simple way to expose dynamic content to assistive technologies, and will hopefully be merged shortly. Give it a +1 on Github if you'd like to see this merged!

###$mdAria.expect

There is an ARIA service method in Angular Material that aims to improve a common accessibility issue: forgotten labels, which add accessible names to elements for assistive technologies. For commonly mislabeled components, such as checkboxes or radio buttons, $mdAria will attempt to copy text content to the aria-label attribute. If no suitable text is found, a warning will be logged to the JavaScript console telling the developer they forgot a label for accessibility. We are fixing bugs with this utility as they come up and evaluating whether it could be useful in ngAria or ngHint.

###Other ideas

Some other things we have discussed or proposed for Angular accessibility: warnings for missing alt attributes, default keyboard bindings such as the escape key or question mark key, color contrast warnings and more. I'm excited to see this list grow as we "dogfood" ngAria on Angular Material and see it battle-tested in the community. If there are things you want ngAria to do for you, please write about it in the comments.


##Common Accessibility Challenges

Some things you should consider as you build client-side web applications:

  • Text alternatives: Be sure to add alternate text content to make visual information accessible. This can be accomplished using different techniques described in these handy guidelines. The appropriate technique depends on the markup but can be accomplished using offscreen spans, aria-label or a label element, image alt attributes and figure/figcaption elements.
  • HTML Semantics: If you're creating custom element directives or writing HTML in general, be sure to make use of native elements wherever possible. Alternatively, use ARIA to add semantic meaning. See notes on ARIA use.
  • Focus management: Guide the user around the app as views are appended/removed. Focus should NEVER be lost, as this causes unexpected behavior and much confusion (referred to as "freak-out mode").
  • Color contrast and scale: Make sure content is readable and legible on all screen sizes. Consider configurable color schemes or personalizable UIs for people with color blindness, low vision or other visual impairments.

It is our responsibility as developers to make accessible web applications that are well-tested. However, the frameworks we use should do as much as possible to improve accessibility by default. As a new module, ngAria will continue to evolve as we discover common use cases it can handle or warn about. Balancing performance and developer experience with end-users' needs requires careful planning and execution, which means it will take time to get right. Consider contributing on Github if you have ideas for ngAria and by all means, feel free to comment!

##Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment