Accessibility guidelines

The aim of this documentation is to help developers to understand how to implement accessibility guidelines.

TLDR

1. Use the semantic elements

E.g. If the element acts like a button, use a <button>, if it is navigation, use <nav>

2. Check contrast

Ensure all elements pass at least WCAG AA

3. Check the document outline

Ensure that headings (<h1> to <h6>) are in the correct order with no skips

4. Add aria states and properties

Using aria states and properties can provide extra information to users

5. Browse the site using the keyboard

At the very basic level, ensure that pressing tab allows focus on elements that require it. All functionality shoud be accessible without using the mouse

6. Image alternative text

Make sure images have alternative text if they need it, leave the alternate text blank if they do not

7. Resizing

Ensure the code scales well if the user were to zoom in, or set they browser to increase the font size

8. Use automated testing tools

Uses tools such as WAVE Web Accessibility Evaluation Tool to check for any errors with your code

9. Use a screen reader

Use a screen reader to ensure the code makes sense to users who don't browse the site visually

Semantic elements

Use the correct markup

Using the correct HTML markup will often result in the desired accessibility behaviour. This can save a lot of time and effort.

For example, compare how a screen reader interprets the following elements, visually they are identical, but semantically the first example is easier to navigate when using a keyboard, and provides a more detailed read-out in a screen reader.

Heading

  • List item 1
  • List item 2
  • List item 3
Heading
List item 1
List item 2
List item 3

Roles

What are roles?

The role attribute can be added to an element to help screen readers understand its function. In general it is preferable to use standard HTML elements which natively have their role, rather than adding a role to an element.

Common roles used in the Design Framework

There are a variety of resources online which list the available roles, so here is a curated list of some of the roles we have found most useful:

  • role="alert" - Typically used to notify a user of a change on the website. Screen readers will automatically detect a change in content and read it out.
  • role="application" - Tells screen readers that the element and all its children should be treated as a desktop application. Using this role will stop the element from reacting to key presses in the standard way, so will require custom JavaScript to enable keyboard navigation.
  • role="button" - Makes the element clickable, often needed if the element has a JavaAscript click event attached to it. In general, using a <button></button> would be preferable.
  • role="combobox" - A widget that contains a text input which reveals a list of results based on the entered text. Requires a role="listbox" child element, which has multiple role="option" child elements.
  • role="dialog" - Signifies that the content is a sub-window and should be treated separately from the rest of the page.
  • role="listbox" - Used in conjunction with role="combobox". This is the list that contains the selectable options.
  • role="option" - Used in conjunction with role="listbox". This is an option in the list.
  • role="region" - An area of the page which contains a group of similar elements.
  • role="status" - A region that contains advisory information, but is not important enough to justify using role="alert".
  • role="tab" - An individual tab in a role="tablist" which opens a role="tabpanel".
  • role="tablist" - A list of role="tab" which open role="tabpanel".
  • role="tabpanel" - An panel in a role="tablist" which is opened when a role="tab" is selected.
  • role="tooltip" - A popup that is revealed to show information about an element.

More information on roles

Aria states and properties

What are states and properties?

States and properties fulfil similar roles as they detail information about a particular element. Properties (such as aria-label) are unlikely to change, while states (such as aria-busy) will often change and describe the current status of the element.

States and properties are vital to screen readers as it helps them offer information about the element that would otherwise only be apparent to users visually inspecting the website.

Common states and properties used in the Design Framework

There are a variety of resources online which list the available aria states and properties, so here is a curated list of some of the states and properties we have found most useful:

  • aria-activedescendant - Contains the ID of the currently active child element, for example the currently selected item in a combo box.
  • aria-autocomplete - Indicates whether a text input can trigger autocomplete suggestions.
  • aria-busy - Indicates that something is happening in/to the element and for the screen reader to wait before alerting the user.
  • aria-controls - A list of ids of elements controlled by the current element.
  • aria-current - Indicates the the element is the current item.
  • aria-describedby - Contains the id of an element that describes the current element.
  • aria-disabled - Indicates that the element cannot be interacted with.
  • aria-expanded - Indicated if the element is expanded or collapsed.
  • aria-hidden - Indicates whether the element is visible to the screen reader. This can allow the element to be visible on screen, but ignored by the screen reader.
  • aria-invalid - Indicates whether the entered value is valid on form elements.
  • aria-label - A value that labels the current element.
  • aria-labelledby - Contains the id of an element that labels the current element.
  • aria-live - Indicates that the element will be updated and how the screen reader should notify the user.
  • aria-modal - Indicates that this element is a modal.
  • aria-pressed - Indicates whether the current element (usually a button) is pressed.
  • aria-required - Indicates that the current element is required.
  • aria-sort - Indicates the current sort order.

More information on states

Screen readers

Unfortunately, like browsers, screen readers come with their own unique set of quirks.

Screen readers do not all read content out in the same way,

There is not a set standard on how screen readers should convey marup, so keep in mind that something that reads in the desired way in one screen reader, my not read the same way in another. For example, focus on the following link in Chrome using NVDA, and then using Windows Narrator:

Link text

NVDA will read:

Aria label text visited link Title text

Windows Narrator will read:

link Aria label text

Windows Narrator omits the title text, so if this text was crucial to the user understanding the context of the link you would need to find another way of communicating this information.

Unique combinations of screen readers and browser can result in different behaviour

Testing a screen reader in one browser unfortunately isn't enough as using the same screen reader in different browser can lead to different read outs. For example, listen to how NVDA reads out the following list in Chrome/Edge and Firefox:

Qualification
BA (Hons)
Duration
4 years
Study mode
Full-time
Start date
2016

Chrome will read:

list with 8 items Qualification BA (Hons) Duration 4 years Study mode Full-time Start date 2016 out of list

Firefox will read:

list with 8 items Qualification BA (Hons) blank Duration 4 years blank Study mode Full-time blank Start date 2016 out of list

Notice the additional "blank" that is read out in Firefox.

There are multiple ways to navigate sites while using screen readers, each of which may come with their own complications

Using tab to cycle through focusable elements is only one way of navigating websites using a keyboard. Each screen reader has their own methods, shortcuts and key combinations to allow navigation of websites.

Tabindex

How to use tabindex

tabindex is extremely important to anyone with sight impairment.

It allows easy and predictable keyboard navigation of all page elements that one would normally interact with using a pointing device.

By default the browser works out the logical order of all the keyboard focusable elements on the page, based on source order. You should only modify this native behaviour when absolutely necessary and adhere to the following rules.

1. Do not use a positive value for tabindex

Doing so creates an artificial order for keyboard navigation. Subsequently, the source order could be different to the tab order. This can be confusing if you are relying on a screen reader and keyboard to navigate the page as the page would not follow a logical tab order.

2. Use tabindex="0" to enable keyboard focusing on elements not natively focusable

e.g. span, div, p. Any element with tabindex="0" will have its tab order dictated by the logical order of the markup and therefore be focusable via the keyboard in a logical, predictable way. In general, if you are adding tabindex="0" to make an element focusable, you should consider using a more suitable element for the task e.g. button, a, input

3. Use tabindex="-1" to change focus programmatically

Adding tabindex="-1" will stop users from being able to tab to the element while still allowing it to be focussed programmatically (i.e. by JavaScript). This can be useful when an item needs the focus set on them but should not be tabbed to via the keyboard. For example, you may want to set the focus on a modal that has just openned without letting the user focus on it when using the keyboard.

Further reading

Widget examples

Tabs

The following is the suggested pattern for displaying tabs.

Key mapping
Key Action
tab ⇥
  • When moving into the tab list, focuses on the currently active tab.
  • When within the tab list, focuses on the currently active tabpanel.
shift ⇧ + tab ⇥
  • When moving into the tab list, focuses on the currently active tab.
  • When within the tab list, focuses on previous focusable element outside of the tab list.
Home Focuses on the first tab and activates it.
End Focuses on the last tab and activates it.
left ←
  • Focuses on the next tab and activates it.
  • If current focus is on first tab, focuses on the last tab and activates it.
right →
  • Focuses on the previous tab and activates it.
  • If current focus is on last tab, focuses on the first tab and activates it.
Etiam eleifend nulla sed urna vulputate, ac venenatis nibh ornare
Sed consequat dui sed arcu volutpat rutrum
Nunc facilisis odio a orci congue, vitae semper leo aliquam
Sed consectetur justo metus, ac mattis augue scelerisque in
Ut ultricies, neque id blandit mollis, nisl turpis vulputate mauris, vitae auctor tellus dolor eget neque

More information on tab patterns

Comboboxes

The following is the suggested pattern for displaying comboboxes.

Key mapping
Key Action
tab ⇥
  • When moving into the combobox, focuses on search input.
  • When within the combobox, focuses on the next focusable element outside of the combobox and closes the combobox suggestions if it is open.
shift ⇧ + tab ⇥
  • When moving into the combobox, focuses on search input.
  • When within the combobox, focuses on previous focusable element outside of the combobox and closes the combobox suggestions if it is open.
Esc Closes the combobox suggestions if it is open.
Enter Selects an option when it is highlighted.
right →
  • When in the search input, move the caret right.
  • Selects an option when it is highlighted.
up ↑
  • Focuses on the next option.
  • If current focus is on first option, focuses on the last option.
down ↓
  • Focuses on the next option.
  • If current focus is on last tab, focuses on the first option.
right →
  • Focuses on the previous tab and activates it.
  • If current focus is on last tab, focuses on the first tab and activates it.

More information on combobox patterns