Accessibility for developers
Every interactive thing on a web page needs an accessible name. The most important thing to remember is to use HTML as far as possible and only add ARIA when necessary.
What's the accessible name of this thing?
Each interactive thing on a page needs the following:
- Identity
- Operation
- State
Operation and state are communicated by the control itself (e.g. a checkbox can be checked or unchecked, and its state is communicated to the user). For custom controls we need to add these with ARIA attibutes.
Identity is the control's name. The name should usually be visible on screen, but an accessible name can be visually hidden or supplied by an ARIA attribute (and therefore not visible on screen). Here are some things to keep in mind:
- Every form control needs a name (visible or not)
- Every group of controls needs a name (visible or not)
- Generally you should use (correctly marked-up) visible names as they work for all users
- When we don't use the right HTML, things can be invisible or opaque to screen reader users
Links and buttons
Links
Links are used to navigate the user to a new page or view or bit of a page: to move away from current context. Follow this guidance:
- Links are focusable by default when they have an
href
attribute (no need to add atabindex
) - Links respond with a click event to the Enter key
- Links can't be disabled (they can be made inert with
tabindex="-1"
andaria-hidden="true"
, but be sure that's what you need) - Links should accept
:link
,:visited
,:focus
,:hover
,:active
styles - Links are communicated as links to screen readers (no need to add
role="link"
)
Further considerations:
- When an image is inside a link, the image's alt text becomes the accessible name of the link
- When link text is repeated on a page (e.g. 'Read more'), we can use
aria-label
to provide a longer unique name (e.g. 'Read more: {{ article name}}')
When using links do the following:
- Do add
alt
text to an image that's the content of ana
. Good alt text succinctly conveys the function and meaning of the image. - Do make sure links are visually distinct from the surrounding text.
- Do make sure
:focus
styles are clear and distinct from the regular styles. - Do try and make link text unique on the page. This benefits users of assistive tech and makes for better UX. When link text is repeated on a page (e.g. 'Read more'), we can use
aria-label
to provide a longer, unique, name (e.g. 'Read more:{{ article name}}
') - Do add
aria-current="page"
to thea
in a nav list, if it's the current page.
Here is some guidance about what to avoid when using links:
- Don't add a
title
attribute - use the text of the link instead. - Don't wrap chunks of content in an
a
, even though it's technically allowed in the spec. Screen readers read the whole chunk of content as the content of the link (rather than the more appropriate 'Read the rest of this article.') - Don't use a link with
href="#"
 - in this case you should probably be using a button.
Buttons
Buttons are for completing actions such as submitting forms or showing/hiding things.
- A
button
inside aform
has an implicittype="submit"
(no need to add it) - Other buttons should have a
type="button"
to avoid automatically submitting a form - Buttons receive keyboard focus by default (no need to add
tabindex
) - Buttons respond with a click event to the Space key or Enter key
- Buttons can be disabled with the
disabled
attribute - Buttons are communicated as buttons to screen readers (no need to add
role="button"
) - Buttons accept
:focus
,:hover
,:active
,:disabled
styles
When using buttons do the following:
- Do always provide an accessible name.
- Put text inside the button. If there's also an image, that can have
alt=""
. - Use an
aria-label
on thebutton
oralt
text on the image if the image is the only thing inside thebutton
.
- Put text inside the button. If there's also an image, that can have
- Do make the accessible name describe the action that will occur when the user hits the button. Ideally it should be unique too, e.g. 'Show messages' rather than just 'Show'. This benefits users of assistive tech and makes for better UX.
- If you make a
button
disabled, ensure that you explain why. Usearia-describedby
to point at the ID of the element containing the explanation.
Do not add div
s as children elements of a button
 - but you can add inline things like span
s.
Things to watch out for
- Adding a
tabindex="0"
to make an element focusable. Can you use a focusable element like ana
or abutton
instead? - Adding a
role="button"
orrole="link"
. Can you use abutton
ora
element instead? - Using a
div
or aspan
for an element that does an action like navigation or show / hide. Can you use ana
or abutton
instead? - Using
href="#"
on ana
(i.e. a link that goes nowhere). Can you use a button instead? - Using
disabled
on ana
. That's not a valid attribute on ana
. Can you use a button instead? - Having identical accessible names for a repeated links or buttons (e.g. a column of 'Edit', 'Edit', 'Edit').
You can make a div
or a span
into a link or a button by adding a role
, tabindex="0"
, and handlers for click, Space, and Enter events. However, this is creating more work for yourself, so please just use an a
or a button
instead.
Single form controls
There are a couple of ways of adding a name. Here are our options, in order of preference. Only use one of the following methods:
- A
label
withfor="id-of-the-control"
- An
aria-labelledby="id-of-the-visible-text-that-works-as-a-label"
on the form control - A
label
withfor="id-of-the-control"
that's visually hidden using oursr-only
utility class - An
aria-label="The label for the form"
on the form control
aria-describedby
does not supply an accessible name. It's only for additional information such as an error message on a field, formatting requirements, or password character requirements.
Groups of form controls
Radio buttons and checkboxes come in groups and need a name for the group (in addition to a name each item). Other things that come in logical groups (such as address fields, or login forms with a username and password) can benefit from a name for the group. Here are our options for naming groups, in order of preference:
- A
legend
element with the group name. Note that this must be the first child element of afieldset
. - An
aria-labelledby="id-of-the-visible-text-that-works-as-a-label"
on the element containing the group name. Note that the group must also an have an ariarole
. - An
aria-label="The name of the group"
on the group container.
We can't use label
to provide a name for a group of controls, only for a single form control.