/
Writing accessible code
Writing accessible code
HTML / structured content
Semantic HTML gives us lots of accessibility features for free. Browsers and assistive technology know what to do with the markup. Here is some general guidance to follow:
- Validate the HTML.
- Use the correct element - only use a
div
orspan
if no other element fits the purpose. Don’t pick an element for purely presentational purposes. - Add a skip link for keyboard users as the first thing on the page, pointing at
main
. - Add the following elements as direct children of
body
:<header>
;<main>
;<aside>
;<footer>
. - Add
<nav>
s (with aul
of links inside). - Use heading elements (
<h1>
to<h6>
) and do not skip any levels (e.g. going from<h1>
to<h3>
). - Use
<section>
s to group content thematically, each with a header. - Use
<article>
s for self-contained things like a blog post or a single product, each with a header. - Mark
table
s up correctly (and don’t use them for layout purposes). They should have a<caption>
,<th>
s for the table headers that havescope
attributes for row or column (as appropriate). - Add a
lang
attribute to content not in the main language of the document. - Add ARIA attributes carefully - use only semantic HTML where possible. See W3C's Using ARIA for more.
- Check that accessible names are consistent with visible names, if they’re set separately.
- Decorative images should have
alt=""
or be applied with CSS as abackground-image
. - Have a site map, search function, or
link rel
s.
Custom elements
Take extra care with custom elements. View the accessibility tree and make sure that custom elements have the following:
- Name (this may already be set from a
label
) - Role (see ARIA Design Pattern Examples)
- Current value (may already be set from an
input
) - Has
:focus
styles - Has an element with
aria-live
, if required
Forms
Here is some guidance to follow when coding forms:
- Every form control must have an accessible name associated with it. Pick just one of these methods:
- A label with
for="id-of-the-control"
(preferred method) - An
aria-label="The label for the form"
on the form control - An
aria-labelledby="id-of-the-text-that-works-as-a-label"
on the form control
- A label with
- There should be a heading.
- Every group of related controls should have a
<fieldset>
with a<legend>
. - Every appropriate field should have an
autocomplete
attribute with the appropriate value. See the WCAG Input Purposes for User Interface Components list. - Use HTML5
input
type
s to aid user input.
Errors
Here is some guidance on how to handle error messages in your code:
- Where possible, have error messages as children elements of label elements.
- Where not possible, use
aria-describedby="id-of-the-error-message-element"
on the form control. - Add
aria-invalid
to invalid fields using client-side scripting. - Add
aria-required
to mark required fields as well as the HTML5required
attribute.
CSS / presentation
Here are some tips for using CSS in an accessible way:
- Only use CSS for layout and formatting, not whitespace in the HTML.
- Make all click or touch targets at least 44 x 44 pixels (except when inline in a block of text).
- Set a
background-color
whenever acolor
is set. - Use responsive web design.
- Don’t set fixed width containers (that would clip, truncate, or obscure text, or cause horizontal scrolling, when text is enlarged).
- Don’t use viewport-based units for font size.
- Try to avoid flashing content (AAA). Any areas with flashing should be small (about thumbnail size), and flash fewer than three times a second (AA).
JS / behaviour
Here are some tips for using JS in an accessible way:
- Every component should be keyboard accessible, and users should be able to tab in to and out of it (AA allows for some exceptions).
- The tab order should also be logical. Don’t add
tabindex
if you can avoid it.
- The tab order should also be logical. Don’t add
- Use input-agnostic event handlers (
focus
,blur
,click
), not touch-only. - Only perform actions at the end of an event, not on down events. Alternatively, provide an undo option.
- Try to avoid hiding content behind a
hover
. If you do, make sure:- The revealed content can be hovered on too
- It can be dismissed by moving the pointer or changing focus (e.g. using
Esc
) - It stays until it’s dismissed
- Any audio or video should have pause / stop controls, and should not autoplay.
- Don’t use automatic redirects like
meta
refresh
andredirect
. - Have pause, stop, and hide controls for any moving, blinking, or scrolling content.
- Any character key shortcuts should be able to be turned off, remapped, or are only active on focus.
- Components should be accessible by default, by having a prop-based option for turning off the added accessibility features, in case the components are being combined in a different way.