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
hrefattribute (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,:activestylesLinks 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-labelto provide a longer unique name (e.g. 'Read more: {{ article name}}')
When using links do the following:
Do add
alttext 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
:focusstyles 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-labelto provide a longer, unique, name (e.g. 'Read more:{{ article name}}')Do add
aria-current="page"to theain a nav list, if it's the current page.
Here is some guidance about what to avoid when using links:
Don't add a
titleattribute - 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
buttoninside aformhas an implicittype="submit"(no need to add it)Other buttons should have a
type="button"to avoid automatically submitting a formButtons 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
disabledattributeButtons are communicated as buttons to screen readers (no need to add
role="button")Buttons accept
:focus,:hover,:active,:disabledstyles
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-labelon thebuttonoralttext on the image if the image is the only thing inside thebutton.
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
buttondisabled, ensure that you explain why. Usearia-describedbyto 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 anaor abuttoninstead?Adding a
role="button"orrole="link". Can you use abuttonoraelement instead?Using a
divor aspanfor an element that does an action like navigation or show / hide. Can you use anaor abuttoninstead?Using
href="#"on ana(i.e. a link that goes nowhere). Can you use a button instead?Using
disabledon 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
labelwithfor="id-of-the-control"An
aria-labelledby="id-of-the-visible-text-that-works-as-a-label"on the form controlA
labelwithfor="id-of-the-control"that's visually hidden using oursr-onlyutility classAn
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
legendelement 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.