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
 orÂspan
 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 aÂul
 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 haveÂscope
 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 aÂbackground-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 HTML5Ârequired
 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 aÂcolor
 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
 andÂredirect
. - 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.