DEV Community

Cover image for Simple Steps to Ensure Accessibility in Your Angular Projects
Dany Paredes
Dany Paredes

Posted on • Originally published at danywalls.com

Simple Steps to Ensure Accessibility in Your Angular Projects

When we build apps, we usually focus on delivery rather than covering other aspects like Accessibility and Testing (but testing will be covered in another post). Today, I want to talk about Accessibility. Most of the time, we think accessibility is just to help people with disabilities use our product, but it actually improves the experience for all users.

In December, I spent some time learning about Accessibility, and I highly recommend taking these free courses.

This weekend, I took time to test the skills I learned by building a small form that includes accessibility from the start, including form setup and validation. Let's do it!

I wanted to create the "Letter to Santa" form where my son can send his name, email, and a message to Santa Claus, but I want to build an accessible form with clear and accessible validations and a notification when the message has been successfully sent.

Finally, I got a form like this:

Final Resul


The main goal of the form is to collect information from users. If forms are not accessible, we exclude a significant portion of people, such as users with visual or motor impairments, or those affected by a temporary accident or with their hands busy.

I started improving accessibility by using semantic HTML elements like <header>, <main>, and <footer>, and organizing content hierarchically with headings (<h1> to <h6>). This helps screen readers navigate the page correctly and also improves SEO.

<header>
  <h1>Write Your Letter to Santa</h1>
</header>
<main>
  <h2>Fill Out the Form</h2>
</main>
<footer>
</footer>
Enter fullscreen mode Exit fullscreen mode

The main goal of the form is to collect information from users. If forms are not accessible, we exclude a significant portion of people, such as users with visual or motor impairments, or those affected by a temporary accident or with their hands busy.

I started improving accessibility by using semantic HTML elements like <header>, <main>, and <footer>, and organizing content hierarchically with headings (<h1> to <h6>). This helps screen readers navigate the page correctly and also improves SEO.

<label for="name">Name</label>
<input id="name" name="name" required type="text" />
Enter fullscreen mode Exit fullscreen mode

But forms are more than just input and label; they need validations or error messages that should only appear when relevant, such as after a field has been interacted with (touched) or when the form is submitted. But how do I notify the user with a message?

First, the notifications should be announced by screen readers using aria-live with a visually clear design for users who do not use assistive technologies and avoid unnecessarily interrupting the user.

Learn more about aria-live and roles

There are different ARIA roles to use with the notifications for specific scenarios, using role="alert" for critical or high-priority messages, such as errors. It automatically interrupts the user and announces the content immediately, or role="status" for non-critical updates, such as confirmations or status changes.

    <div class="error" role="alert">
      <p>Name is required.</p>
    </div>
Enter fullscreen mode Exit fullscreen mode

But how are those messages announced? You have assertive, which stops the current message, or polite, which waits to announce by screen readers without interruption.

@if ((nameCtrl.invalid && nameCtrl.touched) || (nameCtrl.invalid && isSubmitted)) {
  <div class="error" role="alert">
    <small>Name is required.</small>
  </div>
}
Enter fullscreen mode Exit fullscreen mode

For example, aria-live="polite" waits to announce the content after completing its current task. It is perfect for notifications like when a message has been sent:

    @if (messageSent) {
      <div class="notifications" role="status" aria-live="polite">
        <p>{{ message }}</p>
      </div>
    }
Enter fullscreen mode Exit fullscreen mode

But what happens when I want content only for screen readers? We can create a utility class like .visually-hidden for content that is only meant to be accessible to screen readers and not visible to sighted users.

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
Enter fullscreen mode Exit fullscreen mode

It helps to ensure that essential information is conveyed to users relying on screen readers without affecting the visual layout.

<span class="visually-hidden">Error:</span>
<p>Name is required.</p>
Enter fullscreen mode Exit fullscreen mode

Another key point is also is the color, with adequate contrast, the text should have sufficient contrast with its background according but most easy way is using the color-contrast-checker extension.

input.ng-invalid.ng-touched {
  border-color: #e74c3c; 
  background-color: #fdecea; 
}
Enter fullscreen mode Exit fullscreen mode

Perfect we can build our form ready with accesibility!! Hey hold a second ? What happend if tomorrow @Jörgen de Groot add a new feature , how I can control he don’t break the accesibility ?

The es-lint is your friend, first add using the schematics:

ng add @angular-eslint/schematics
Enter fullscreen mode Exit fullscreen mode

The es-lint provide a set of accessiblity rules like accessibility-label-has-associated-control to ensures that every label element has an associated form control (similar to accessibility-label-for but stricter).

<!-- Incorrect -->
<label>Email</label>

<!-- Correct -->
<label for="email">Email</label>
<input id="email" type="email">
Enter fullscreen mode Exit fullscreen mode

or accessibility-table-scope, requires data table headers (<th>) to have a scope attribute, improving navigation for screen readers.

<!-- Incorrect -->
<th>Name</th>

<!-- Correct -->
<th scope="col">Name</th>
Enter fullscreen mode Exit fullscreen mode

Feel free to read more about accesibility es-lint, add these rules to the file (.eslintrc.json), adjusting the severity ("warn", "error", etc.) as needed:

{
  "overrides": [
    {
      "files": ["*.component.html"],
      "extends": ["plugin:@angular-eslint/template/recommended"],
      "rules": {
         "@angular-eslint/template/accessibility-elements-content": "error",
        "@angular-eslint/template/accessibility-valid-aria": "error",
        "@angular-eslint/template/accessibility-label-has-associated-control": "warn",
        "@angular-eslint/template/accessibility-table-scope": "error",
        "@angular-eslint/template/accessibility-role-supports-aria": "warn",
        "@angular-eslint/template/accessibility-click-events-have-key-events": "warn",
        "@angular-eslint/template/accessibility-no-positive-tabindex": "error",
        "@angular-eslint/template/accessibility-media-has-caption": "warn",
        "@angular-eslint/template/accessibility-valid-tabindex": "error",
        "@angular-eslint/template/accessibility-input-label": "warn"
        "@angular-eslint/template/accessibility-role-has-required-aria": "error"
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

After run npm run lint tada!! we have a linter for our code!

Lint result

Recap

I hope when you start to create your next project, keep in mind these tips to simplify your accesibility and take care to improve our apps for all users.

Top comments (0)