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 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 a tabindex)
  • Links respond with a click event to the Enter key
  • Links can't be disabled (they can be made inert with tabindex="-1" and aria-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 an a. 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 the a 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 are for completing actions such as submitting forms or showing/hiding things.

  • A button inside a form has an implicit type="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 the button or alt text on the image if the image is the only thing inside the button.
  • 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. Use aria-describedby to point at the ID of the element containing the explanation.

Do not add divs as children elements of a button - but you can add inline things like spans.

Things to watch out for

  • Adding a tabindex="0" to make an element focusable. Can you use a focusable element like an a or a button instead?
  • Adding a role="button" or role="link". Can you use a button or a element instead?
  • Using a div or a span for an element that does an action like navigation or show / hide. Can you use an a or a button instead?
  • Using href="#" on an a (i.e. a link that goes nowhere). Can you use a button instead?
  • Using disabled on an a. That's not a valid attribute on an a. 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 with for="id-of-the-control"
  • An aria-labelledby="id-of-the-visible-text-that-works-as-a-label" on the form control
  • A label with for="id-of-the-control" that's visually hidden using our sr-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 a fieldset.
  • 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 aria role.
  • 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.