Skip to main content

Keyboard

Many users with motor disabilities rely on the keyboard as well as many blind users. For many enterprise applications efficiency may be the reason to use the keyboard. As an Ionic application can target the web its important to test for keyboard accessibility.

The first step in testing keyboard accessibility is to pressing the Tab key to see what interactive elements you can and cannot reach.

Testing can be done in any web browser or mobile device with a bluetooth keyboard.

You may need to enable tabbing to ensure all interactive controls will focus:

  • For Mac - Visit System Preferences > Keyboard > Shortcuts > Keyboard.
  • For Safari - Visit Safari > Preferences > Advanced and check the box Press Tab to highlight each item on a webpage

Hidden Controls

If you paste the following line in your dev tools console you can see whenever the active control changes and it will reveal controls that are focused but hidden:

document.body.addEventListener('focusin', () => console.log(document.activeElement));

Tips

  • Setting opacity to none or height / width to 0 is often used to hide elements but they are still focusable with the keyboard. Use display: none to truly hide elements.
  • A typical cause for hidden controls is the css outline set to none or 0. Consider custom styling outlines instead.
  • The div element is not focusable. If a div has interactivity then it needs to be fixed (eg by changing to button and changing the style).
  • Test using arrow keys as well as the tab key. Not every element accessible via tab can be accessed via arrow keys (and should be).

You can override default styling for a button when you replace a div. For example:

background-color: transparent;
border: none;
border-radius: 0;

Testing Escape

Pressing the Esc key on the keyboard will close Ionic components like an alertController, ion-picker, ion-menu etc. Make sure to test by pressing Esc on elements you have written and handle by using the keyup event and also be sure to focus() where the user should navigate from next.

Ionic Component Styling

You can add css styling to Ionic components so that during keyboard navigation the focused element is easily visible. For example, this css will show a red border around any element:

ion-input.has-focus,
button:focus-visible,
ion-button.ion-focused,
ion-segment-button.ion-focused,
ion-radio.ion-focused,
ion-select.ion-focused,
ion-fab.ion-focused,
ion-searchbar.ion-focused,
ion-checkbox.ion-focused,
ion-toggle.ion-focused,
ion-range.ion-focused,
ion-datetime.ion-focused,
ion-accordion.ion-focused,
ion-textarea.ion-focused {
outline: 2px solid red;
}

For the above css to work there are some components you will need to add class="ion-focusable" to. This includes: ion-fab, ion-searchbar, ion-checkbox, ion-toggle, ion-range, ion-datetime, ion-accordion, and ion-textarea. For example:

<ion-textarea class="ion-focusable"></ion-textarea>
tip

One important difference between using a psuedoclass like ion-focused and focus is that focus will style the element whether the user focused it through keyboard or by clicking on it. Using ion-focused will mean that the element is only styled when it is focused via the keyboard.

Non-interactive Components

Some components like ion-badge are not interactive but you may want to make them interactive by allowing a user to click on them. Example:

<ion-badge (click)="dostuff()">33</ion-badge>

But, this component cannot be reached through keyboard interaction. So it is better to refactor this to:

<button (click)="dostuff()"><ion-badge>33</ion-badge></button>

You will need to style using focus-visible for the focus area to be visible:

button:focus-visible {
outline: 2px solid red;
}

Focusing Non-interactive Elements

If you have a non-interactive element like a div or span you can focus it by using the focus() method. However, because these elements are not interactive a screen reader will not read the element and the focus will not change.

You can set tabindex="0" on the element to allow it to focus.

<span tabindex="0" #container class="error"> {{ errorMessage }} </span>

You could also set role="button" however, in general it is not a good idea to make non-interactive elements focusable as it interrupts the natural flow of interactive elements, so use this technique sparingly.