Accessibility shiv with AngularJs

Reading time ~1 minute

Implementing Accessibility with AgularJs

####This blog is written with love.

We have recently been using the Web Content Accessibiity Guidelines version 2.0 (WCAG 2.0) to improve the accessibility of our web projects.. In this blog, we will show a creative way to implement the item ARIA2: Identifying required fields with the aria-required property.

The following is a typical input field(input is a void element. the closing “/” is optional.):

<label for="user-name">User Name:</label>
<input id="user-name" type="text"/>

And in the browser, it looks like this in a browser:

text input with label

We would like to add asterisk to the label, if the input field is required:

required input field with label

The HTML element looks like:

<label for="user-name">User Name:<abbr title="required" class="required">*</abbr></label>
<input id="user-name" type="text"/>

There are many fields need to be updated, to make it simple, we are going to do it dynamically with angularjs.

Implementation

Directive asterisk

Let’s create a aterisk directive first.

//HTML

<asterisk></asterisk>

//JavaScript

// ua means usability and accessibility
var uaModule = angular.module('ua', []);

uaModule.directive('asterisk', function(){
  return {
    restrict: 'E', // only apply to Element
    template: '<abbr title="required" class="required"">*</abbr>',
    transclude: 'true',
    replace: 'true' // replace the current element
  }
});

Make sure you have bootstrapped your html with:

angular.element(document).ready(function () {
  angular.bootstrap(document, ['ua']);
});

Now whenever you add an asterisk element in your DOM structure, you will see a “*” on the page.

Please checkout this pluckr: http://plnkr.co/edit/kIIBicQklGuZVDblkw0Z?p=preview

Directive require

required is a new attribute introduced in HTML5, and is supported by all main stream browsers. Though there is a ‘html5shiv.js’ to fix some issue on IE9, I have NOT verified it. Please leave comments, if it does not work on your IE9 with html5shiv.

What we want to achive is have angularjs add the required span when it finds a required attribute on the input element.

First, add required attribute to input element. The code looks like:

<label for="user-name">User Name:</label>
<input id="user-name" type="text" required/>

After the enhancement, it will become:

<label for="user-name">User Name:
	<abbr title="required" class="required">*</abbr>
</label>
<input id="user-name" type="text" required/>
uaModule.directive('required', ['$document', '$compile', function (document, compile) {
  var linkFn, labelNode, labelElement, abbrElement;

  linkFn = function (scope, element, attrs) {
    // eliminate the dependency on jQuery
    labelNode = document[0].body.querySelector("label[for='" + attrs['id'] + "']");
    if (labelNode) {
      labelElement = angular.element(labelNode);
      // @ add asterisk to the label of a required input field
      abbrElement = angular.element('<asterisk/>');
      labelElement.append(compile(abbrElement)(scope));
    }
  };

  return {
    restrict: 'A',
    link: linkFn
  };
}]);

The final plnkr can be found here.