Overview for a11y

The a11y package provides a number of tools to improve accessibility, described below.

ListKeyManager manages the active option in a list of items based on keyboard interaction. Intended to be used with components that correspond to a role="menu" or role="listbox" pattern.

Any component that uses a ListKeyManager will generally do three things:

  • Create a @ViewChildren query for the options being managed.
  • Initialize the ListKeyManager, passing in the options.
  • Forward keyboard events from the managed component to the ListKeyManager.

Each option should implement the ListKeyManagerOption interface:

interface ListKeyManagerOption {
  disabled?: boolean;
  getLabel?(): string;
}

Navigation through options can be made to wrap via the withWrap method

this.keyManager = new FocusKeyManager(...).withWrap();

There are two varieties of ListKeyManager, FocusKeyManager and ActiveDescendantKeyManager.

Used when options will directly receive browser focus. Each item managed must implement the FocusableOption interface:

interface FocusableOption extends ListKeyManagerOption {
  focus(): void;
}

Used when options will be marked as active via aria-activedescendant. Each item managed must implement the Highlightable interface:

interface Highlightable extends ListKeyManagerOption {
  setActiveStyles(): void;
  setInactiveStyles(): void;
}

Each item must also have an ID bound to the listbox's or menu's aria-activedescendant.

TreeKeyManager manages the active option in a tree view. Use this key manager for components that implement a role="tree" pattern.

Any component that uses a TreeKeyManager should do three things:

  • Create a @ViewChildren query for the tree items being managed.
  • Initialize the TreeKeyManager, passing in the options.
  • Forward keyboard events from the managed component to the TreeKeyManager via onKeydown.

Each tree item should implement the TreeKeyManagerItem interface.

The TreeKeyManager will handle focusing the appropriate item on keyboard interactions.

tabindex should also be set by the component when the active item changes. This can be listened to via the change property on the TreeKeyManager. In particular, the tree should only have a tabindex set if there is no active item, and should not have a tabindex set if there is an active item. Only the HTML node corresponding to the active item should have a tabindex set to 0, with all other items set to -1.

The cdkTrapFocus directive traps Tab key focus within an element. This is intended to be used to create accessible experience for components like modal dialogs, where focus must be constrained.

This directive is declared in A11yModule.

<div class="my-inner-dialog-content" cdkTrapFocus>
  <!-- Tab and Shift + Tab will not leave this element. -->
</div>

This directive will not prevent focus from moving out of the trapped region due to mouse interaction.

Regions can be declared explicitly with an initial focus element by using the cdkFocusRegionStart, cdkFocusRegionEnd and cdkFocusInitial DOM attributes. cdkFocusInitial specifies the element that will receive focus upon initialization of the region. cdkFocusRegionStart and cdkFocusRegionEnd define the region within which focus will be trapped. When using the tab key, focus will move through this region and wrap around on either end.

For example:

<a mat-list-item routerLink cdkFocusRegionStart>Focus region start</a>
<a mat-list-item routerLink>Link</a>
<a mat-list-item routerLink cdkFocusInitial>Initially focused</a>
<a mat-list-item routerLink cdkFocusRegionEnd>Focus region end</a>

Note: If you're using cdkFocusInitial together with the CdkTrapFocus directive, nothing will happen unless you've enabled the cdkTrapFocusAutoCapture option as well. This is due to CdkTrapFocus not capturing focus on initialization by default.

InteractivityChecker is used to check the interactivity of an element, capturing disabled, visible, tabbable, and focusable states for accessibility purposes. See the API docs for more details.

LiveAnnouncer is used to announce messages for screen-reader users using an aria-live region. See the W3C's WAI-ARIA for more information on aria-live regions.

@Component({...})
export class MyComponent {

 constructor(liveAnnouncer: LiveAnnouncer) {
   liveAnnouncer.announce("Hey Google");
 }
}

The FocusMonitor is an injectable service that can be used to listen for changes in the focus state of an element. It's more powerful than just listening for focus or blur events because it tells you how the element was focused (via the mouse, keyboard, touch, or programmatically). It also allows listening for focus on descendant elements if desired.

To listen for focus changes on an element, use the monitor method which takes an element to monitor and an optional boolean flag checkChildren. Passing true for checkChildren will tell the FocusMonitor to consider the element focused if any of its descendants are focused. This option defaults to false if not specified. The monitor method will return an Observable that emits the FocusOrigin whenever the focus state changes. The FocusOrigin will be one of the following:

  • 'mouse' indicates the element was focused with the mouse
  • 'keyboard' indicates the element was focused with the keyboard
  • 'touch' indicates the element was focused by touching on a touchscreen
  • 'program' indicates the element was focused programmatically
  • null indicates the element was blurred

In addition to emitting on the observable, the FocusMonitor will automatically apply CSS classes to the element when focused. It will add .cdk-focused if the element is focused and will further add .cdk-${origin}-focused (with ${origin} being mouse, keyboard, touch, or program) to indicate how the element was focused.

Note: currently the FocusMonitor emits on the observable outside of the Angular zone. Therefore, if you markForCheck in the subscription you must put yourself back in the Angular zone.

focusMonitor.monitor(el).subscribe(origin => this.ngZone.run(() => /* ... */ ));

Any element that is monitored by calling monitor should eventually be unmonitored by calling stopMonitoring with the same element.

Monitoring focus with FocusMonitor

Focus Monitored Subtree (blurred)

It is possible to falsify the FocusOrigin when setting the focus programmatically by using the focusVia method of FocusMonitor. This method accepts an element to focus and the FocusOrigin to use. If the element being focused is currently being monitored by the FocusMonitor it will report the FocusOrigin that was passed in. If the element is not currently being monitored, it will just be focused like normal.

Focusing with a specific FocusOrigin

For convenience, the CDK also provides two directives that allow for easily monitoring an element. cdkMonitorElementFocus is the equivalent of calling monitor on the host element with checkChildren set to false. cdkMonitorSubtreeFocus is the equivalent of calling monitor on the host element with checkChildren set to true. Each of these directives has an @Output() cdkFocusChange that will emit the new FocusOrigin whenever it changes.

Monitoring focus with FocusMonitor

Focus Monitored Subtree (blurred)

The cdk/a11y package comes with Sass mixins that produce styles useful for building accessible experiences.

Screen readers and other assistive technology skip elements that have display: none, visibility: hidden, opacity: 0, height: 0, or width: 0. In some cases you may need to visually hide an element while keeping it available to assistive technology. You can do so using the a11y-visually-hidden Sass mixin, which emits the .cdk-visually-hidden CSS class.

If you're using Angular Material, this class is included automatically by Angular Material's theming system. Otherwise, you can include this mixin in a global stylesheet.

@use '@angular/cdk';

@include cdk.a11y-visually-hidden();
<div class="custom-checkbox">
  <input type="checkbox" class="cdk-visually-hidden">
</div>

Some operating systems include an accessibility feature called High Contrast Mode. The cdk/a11y package provides a Sass mixin that lets you define styles that only apply in high contrast mode. To create a high contrast style, define your style inside the high-contrast mixin.

The mixin works by targeting the forced-colors media query.

@use '@angular/cdk';

button {
  @include cdk.high-contrast {
    outline: solid 1px;
  }
}

The high-contrast mixin accepts the optional $target parameter which allows you to specify the value of the forced-color media query. Its value can be either active or none.

Azure & Blue theme selected.