This article is for versions of Angular 2, Angular 4 and later.

Accessibility (a11y) is often an overlooked aspect of building web applications, especially JavaScript Single Page Apps. Things like forms, routing and event handling are often easy to get wrong in a JavaScript framework. In this post we will cover some general best practices for accessibility for your web app as well as more specific topics for Angular apps. This post will be updated over time as Angular a11y features improve or change. For this article we will use the Angular Pokedex app as a example use case.

Buttons

The most common offender to a11y in Angular apps that I have seen are how click events are used. With Angular’s template binding syntax its very easy to create click events on practically anything we want.



<!-- Incorrect -->
<div (click)="save()" class="btn">
  Save
</div>

<!-- Correct -->
<button (click)="save()" class="btn">
  Save
</button>


To keep our application accessible we want to always use the button element for (click) events. This helps in a few different ways. First buttons are easily focusable. Using just the keyboard we can tab to a button element. This help users with any motor disabilities. Using a button as well by default provides a focus style that outlines the button currently focused. This functionality allows it easy to navigate and tab the active button.

Angular a11y focused button

Links (anchor tags) in Angular follow similar rules to buttons when it comes to a11y. With links we want to ensure we don’t remove focus styles. This allows navigation easy to use with keyboards.

Angular a11y focused link

Links should not be used for button click events. If you need a button to look like a link style it with CSS. Links should primarily be used for linking between navigation views.



<!-- Incorrect -->
<div (click)="navigateToAbout()" class="btn">
  About
</div>

<!-- Correct -->
<a routerLink="about" class="btn">
  About
</a>


Using links for navigation provides a few benefits. Links provides context to SEO search engines and a11y tools. With links this makes it clear that the interaction will cause a navigation to elsewhere in our app. Using links for navigation allows our app to be easily shared and bookmarkable.

Forms

In Angular the form system is quite robust and feature rich but there are some best a11y practices to keep in mind when constructing our forms. Most Angular forms follow the same rules for any accessible HTML form.

First recommendation is use HTML form tag. Using a form tag makes it clear to the user that this is a input form to gather data. This also makes it easier for keyboard tabing and navigation. When a HTML form is created it allows saving the form to be triggered by not just a submit button but also using the enter key by default. Using Angular’s Reactive Forms this is fairly easy to do.



<form [formGroup]="searchForm" (ngSubmit)="search()">
  <label for="search">Search</label>
  <input type="text" id="search" placeholder="Search" formControlName="search" />
  <button>Search</button>
</form>


When creating inputs always have an associated label to describe what the input is for. You can do this with the label element tag. If you don’t want a separate label use the the aria-label in combination with placeholder. Inputs also have focus styles just like buttons and link. Make sure to leave the defaults on or if its a custom input make sure to add focus styles back to the input.

Angular a11y focused input

ARIA Attributes

With certain cases in Angular we may want to make a custom component but also want to ensure it is accessible as well. We can add special ARIA (Assistive Rich Internet Applications) attributes to mark our templates in a way that explicitly describes what our component is doing making it more accessible.

In the Angular Pokedex app we have a custom menu nav component that opens and closes as a slide out overlay. In our app we want to use ARIA attributes to explicitly describe when the menu is visible. This helps screen readers understand when dynamic content has entered into view. There are many ARIA attributes with different forms of functionality but for our example we will be using aria-hidden.



<nav class="nav" (click)="navOpen = !navOpen" [attr.aria-hidden]="!navOpen">
  <a routerLink="/pokemon" class="nav__link" [attr.tabindex]="navOpen ? 0 : -1">
    Pokemon
  </a>
  <a routerLink="/about" class="nav__link" [attr.tabindex]="navOpen ? 0 : -1">
    About
  </a>
</nav>


With Angular’s property binding syntax we can easily bind to the attributes of our navigation allowing us to set the aria hidden property with [attr.aria-hidden]="!navOpen". Now when we toggle our nav the Aria attribute is explicitly set to describe when the navigation is visible or not on the view. Find out more about ARIA here.

Summary

There are still many more topics on accessibility such as color contrast and a11y test tools. This just scratched the surface of where Angular and Accessibility meet. To find more resources on a11y check out the fantastic A11Y Project.

Demo