Skip to content

Instantly share code, notes, and snippets.

@marcysutton
Last active August 1, 2023 12:46
Show Gist options
  • Save marcysutton/8e4f6e51d82cb36710c4 to your computer and use it in GitHub Desktop.
Save marcysutton/8e4f6e51d82cb36710c4 to your computer and use it in GitHub Desktop.
ngAria Developer Guide

The goal of ngAria is to improve Angular's default accessibility by enabling common ARIA attributes that convey state or semantic information for assistive technologies used by persons with disabilities.

##Including ngAria

Using ngAria is as simple as requiring the ngAria module in your application. ngAria hooks into standard AngularJS directives and quietly injects accessibility support into your application at runtime.

angular.module('myApp', ['ngAria'])...

Currently, ngAria interfaces with the following directives:

ngModel

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

For those elements using ngModel, 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
  • aria-required

###Example

<md-checkbox ng-model="val" required>

Becomes:

<md-checkbox ng-model="val" required aria-required="true" tabIndex="0">

ngAria will also add tabIndex, ensuring custom elements with these roles will be reachable from the keyboard. 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 from the keyboard. 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).

ngDisabled

The disabled attribute is only valid for certain elements such as button, input and textarea. To properly disable custom element directives such as <md-checkbox> or <taco-tab>, using ngAria with ngDisabled will also add aria-disabled. This tells assistive technologies when a non-native input is disabled, helping custom controls to be more accessible.

###Example

<md-checkbox ng-disabled="disabled">

Becomes:

<md-checkbox disabled aria-disabled="true">

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

ngShow

The ngShow directive shows or hides the given HTML element based on the expression provided to the ngShow attribute. The element is shown or hidden 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, the default CSS of display: none !important, already hides child elements from a screen reader. Where it 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” on each control. This ensures screen reader users won't accidentally focus on "mystery elements". 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. See the fourth rule of ARIA use.

ngHide

The ngHide directive shows or hides the given HTML element based on the expression provided to the ngHide attribute. The element is shown or hidden by removing or adding the .ng-hide CSS class onto the element.

The default CSS for ngHide, the inverse method to ngShow, makes ngAria redundant. It toggles aria-hidden on the directive when it is hidden or shown, but the content is already hidden with display: none. See explanation for ngShow when overriding the default CSS.

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. Conversation is [currently ongoing](angular/angular.js#9254) about whether ngAria should also bind `ng-keypress` to be more useful.

Example

<div ng-click="toggleMenu()"></div>

Becomes:

<div ng-click="toggleMenu()" tabindex="0"></div>

Note: ngAria still requires ng-keypress to be added manually to non-native controls like divs.


##Disabling attributes The attribute magic of ngAria may not work for every scenario. To disable individual attributes, you can use the {@link ngAria.$ariaProvider#config config} method:

angular.module('myApp', ['ngAria'], function config($ariaProvider) {
  $ariaProvider.config({
    tabindex: false
  });
});

##Common Accessibility Patterns

Accessibility best practices that apply to web apps in general also apply to Angular.

  • Text alternatives: Add alternate text content to make visual information accessible using these W3C guidelines. The appropriate technique depends on the specific markup but can be accomplished using offscreen spans, aria-label or label elements, image alt attributes, figure/figcaption elements and more.
  • HTML Semantics: If you're creating custom element directives, Web Components or HTML in general, use native elements wherever possible to utilize built-in events and properties. Alternatively, use ARIA to communicate 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").
  • Announcing changes: When filtering or other UI messaging happens away from the user's focus, notify with ARIA Live Regions.
  • Color contrast and scale: Make sure content is legible and interactive controls are usable at all screen sizes. Consider configurable UI themes for people with color blindness, low vision or other visual impairments.
  • Progressive enhancement: Some users do not browse with JavaScript enabled or do not have the latest browser. An accessible message about site requirements can inform users and improve the experience.

Additional Resources

@marcysutton
Copy link
Author

Thanks @ThomasBurleson!

@btford
Copy link

btford commented Nov 4, 2014

Consider breaking the ngShow and ngHide section up into two paragraphs; it's a little terse at the moment.

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