Accessibility
Accessibility
Accessibility Development Standards
This document defines the best practices for producing websites that are accessible to the widest possible audience of web users.
Table of Contents
- Introduction
- Audience
- Web Accessibility
- Accessible Email Requirements
Introduction
This document draws its recommendations from a combination of practical experience, current industry best practices and published guidelines, including:
Web Content Accessibility Guidelines
The Web Content Accessibility Guidelines (WCAG) are part of a series of standards developed by the W3C’s Web Accessibility Initiative. Most sites are expected to comply with WCAG 2.2 Level AA, and this is the target standard for all Think Company projects.
ARIA
Whereas WCAG efforts focus on the content found on pages, ARIA (Accessible Rich Internet Application Markup) is an effort to add accessibility to the navigation/use of dynamic or advanced user interfaces sometimes used on web pages. Do not use ARIA by default. Apply ARIA attributes only when proper HTML, CSS, and JS do not meet a screen reader user’s needs. Be judicious when deciding the proper ARIA implementation to use. Using an ARIA attribute outside of its specification will cause problems for screen readers. For example, ARIA tooltips do not receive focus or have an actionable element in them. Thus, if you intend to create an actionable tooltip, do not apply role="tooltip" but instead find a role that better fits the purpose of the UI element.
http://www.w3.org/WAI/intro/aria.php
Section 508
Section 508 is an amendment to the Rehabilitation Act of 1973 that requires federal agencies to make electronic information accessible to people with disabilities.
ADA Title II
The U.S. Department of Justice’s April 2024 final rule under ADA Title II requires state and local governments (and their contractors) to conform to WCAG 2.1 Level AA, with phased compliance deadlines through 2026–2027. If you are building for a state or local government client, treat WCAG 2.1 AA as a legal floor and 2.2 AA as our internal target.
Audience
Estimates vary, but most studies find that about one fifth or 20% of the population is affected by some kind of disability. Not all disabilities make it difficult for people to access the web, but those affected are still a significant enough amount of the population.
It’d be unwise to purposely exclude up to 20% of users from web experiences. In the cases of educational institutions and government entities, it would be a violation of the law.
This document will discuss development practices intended to aid users with particular disabilities. No website or application can be 100% accessible to all groups, so we will focus on the following users:
- Users with visual impairment such as blindness, low vision or color blindness. Depending on the impairment, these users might not be able to distinguish between red/green, blue/yellow. Designs must use other visual cues to convey information.
- Users with hearing impairment such as deafness or hard-of-hearing. These users can typically navigate web pages with relative ease, but they need subtitles and captions in order to use video content.
- Users with motor impairment. These users are unable to use a mouse, have slower response times and limited fine motor control. Their actions are usually performed using keyboard-only input or a variety of switch devices including joysticks, sip-and-puff devices and eye-tracking devices. Some users perform actions through the exclusive use of speech recognition software such as Dragon NaturallySpeaking.
- Users with cognitive impairment. Learning disabilities, distractibility, inability to remember or focus on large amounts of information can affect users. While there is a great deal of web content that cannot be made easily accessible to individuals with profound cognitive disabilities, there is much designers and developers can do to increase the ease of use of web content to people with less severe cognitive disabilities.
This list covers a great deal of users with disabilities, but there are those who are still not covered. For example, it is difficult to determine the number of users affected by multiple disabilities such as low motor control and blindness.
Web Accessibility
Keyboard Accessibility
A central component of making websites accessible is ensuring the site is equivalently navigable with the keyboard as with the mouse, as some of the impairments outlined above do not allow for mouse usage at all. A typical keyboard user can tab forward and backward in a specific sequential order through certain elements on the page. Sometimes the arrows are used for navigation. Users can interact with elements with the enter button and spacebar. Design and develop so that keyboard users receive equivalent forms of the feedback and information conveyed to mouse users. It’s very easy to accidentally hinder this functionality by hiding or rearranging elements in a way that goes undetected by keyboard navigation.
Also respect users who have indicated they prefer reduced motion. Wrap non-essential animation in a @media (prefers-reduced-motion: reduce) query and disable it. Animation that conveys meaning (a loading spinner, a state transition) should still be present but minimized.
Visual Focus States
To arrive at an element with keyboard navigation is to give that element a focus state. When an element has focus, it is the only element that will respond to enter/spacebar keypresses. It is important that the user knows which element has focus at all times, so they know which element they are currently able to interact with, and position of their focused element on the page. Screen readers will read the information in the focused element, but if the user is not using a screen reader, they should still be able to tell where they are on the page through visual cues. A keyboard accessible page will include a detectable focus state on a component for when keyboard users arrive at the component, similar hover state for mouse users. A high contrast and/or colorful outline, a change in text size/style, a change in perceived depth of the focused element are common ways to do this. A combination of those attributes is the strongest solution.
Prefer the :focus-visible pseudo-class over :focus when styling focus indicators — :focus-visible only applies the indicator when the browser determines a focus ring is warranted (typically keyboard navigation), so mouse clicks don’t trigger a stray outline. WCAG 2.2 SC 2.4.11 (Focus Not Obscured) and 2.4.13 (Focus Appearance) now place stricter requirements on focus indicators: the indicator must have at least a 2 px outline and a 3:1 contrast against adjacent colors.
Keyboard navigation concerns permeate many aspects of our accessibility guidelines. Other sections in this document will contain further details including the tab order, toggling element visibility, and navigation skip patterns.
Support
Our current list of expected supported assistive tools and browsers.
- NVDA + Firefox (Windows) — primary
- VoiceOver + Safari (macOS)
- VoiceOver + Safari (iOS)
- TalkBack + Chrome (Android)
Use the axe browser extension for automated accessibility checks during development.
Document Structure & Semantics
Good, semantic structure of your document can be a great asset to accessibility. Page structure informs screen readers of the order through which to present the information on the page, and thus proper semantic page structure will guide the user easily and intuitively through the site.
Initial Markup
Creating web pages that meet our accessibility criteria starts with including important information about the document you are writing in the head.
Language and Localization
Ensure the language of the page is explicitly set. Always declare the default language for text in the page using attributes on the html tag. This signals to screen-readers what language to read the document content in. Do not use the meta element with http-equiv set to Content-Language. If you are unable to update the language value when the language changes due to framework constraints, it is better to leave the language attribute altogether.
<html lang="en"></html>When switching languages on the page, make this explicit as well with the <lang> attribute.
Example:
<p>This sentence is in English.</p>
<p lang="es">Esta frase es en español.</p>
(Spanish)Page Titles
The title element is read by screen readers on every page view. Make the title short and unique.
Meta Tags
There are a couple specific things to keep in mind when addressing meta tags and accessibility.
- Do not include a maximum scale in the viewport meta tag. You would be restricting the pinch zoom functionality that is crucial for many users to see page content.
- Do not prevent user scalable in the viewport meta tag
- Include a character encoding meta tag to alert assistive devices of the character set being used.
Bad:
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>Good:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8" />Semantics
Writing good, accessible semantic HTML is akin to writing good instructions for screen-readers and assistive technologies. Using HTML5 semantic structure tags like <header>, <main>, <article>, <aside>, <footer> will go a long way to formatting your document in a highly accessible manner. Their presence creates a logical, intuitive order through assistive relationships that screen-readers will recognize. Text semantic tags also should be used when appropriate, but do not register with assistive tools.
Headings
Proper heading hierarchies are crucial to highly accessible document structure & semantics. HTML5 allows using <h1...6> tags anywhere on the page, but semantically, it’s important to adhere to principles of consistency and clarity to direct accessibility tools on the page.
An <h1> tag will typically contain a kind of page title. Do not use more than one <h1> tag per page. <h2> tags appear often as the title of a section of the page, like a hero or sidebar.
It’s important to address font-size choices with CSS. Do not use an <h5> for your page title just because it should be smaller.
Furthermore, language in the WCAG 2.0 success criterion for headings revolves around clarity. Headings that are clear and concise help users understand what the content of the page is.
Example:
<h1>What People Eat</h1>
<p>Information about the food people eat.</p>
<h2>Fruit</h2>
<p>Sweet and often juicy food that grows on plants</p>
<h3>Apple</h3>
<p>
A fist-sized round fruit that grows on trees. Often red or green outside with
a crisp and pale colored inside.
</p>
<h3>
Grape/h3>
<p>
A quarter-sized round fruit that grows in bunches on vines. Thin skin and
very juicy.
</p>
</h3>Paragraphs and Text
Visibility is the main subject of text accessibility. If a text-color and its background do not contrast enough, many users will not be able to read it. Standard text and images of text should have a contrast ratio of 4.5:1. Large scale text (font-size of at least 18 point, or 14 with bold) need only contrast at a 3:1 ratio.
A good guide to this can be found at Halters Web, and you can directly test your text & background colors’ contrast ratio at Web Aim Contrast Checker.
Lists
When creating a list on your page, know that screen-readers benefit from well-formatted semantically structured lists using ol, ul, dl, and li tags. These semantics create the assistive relationships between elements on the page that accessibility tools depend on to present information coherently.
One or two navigation link lists on a page should be a guiding principle (i.e. at the top and in the foot). Wrap these in a <nav> element.
Bad:
<div class="product-ctas">
<a href="more.html">More Info</a>
<a href="options.html">Other Options</a>
<a href="sign-up.html">Sign Up Now</a>
</div>Good:
<nav>
<ul class="main-nav">
<li><a href="my-account.html">My Account</a></li>
<li><a href="shop.html">Shop/Upgrade</a></li>
<li><a href="support.html">Support</a></li>
<ul>
</nav>Skip Navigation
Keyboard and screen-reader users start at the beginning of the page and wade through the content sequentially. Sometimes, this means wading through numerous menus, navigation links or other sections before arriving at the main content. For some users, this is a major inconvenience. A “Skip Navigation” link provides the opportunity to bypass all of that and relocate the focus of the assistive technology to the main content of the page.
In content, it might look like:
<body>
<a href="#maincontent">Skip to main content</a>
... 3 Menus, a search bar, etc.
<main id="maincontent">
<h1>Heading</h1>
<p>This is the first paragraph</p>
</main>
</body>In order to hide this element from regular users while maintaining its functionality, it is common to make the link at the very top of the page, but hidden by default with CSS. Then when a user first engages with keyboard navigation, it is the first link to receive focus and can be revealed with CSS.
Set tabindex="-1" on the skip-link target so that focus can be moved to it programmatically when the link is followed. Do not add role="main" to a <main> element — <main> already has an implicit role of main, and redundant ARIA roles are flagged by linters (axe, ESLint a11y plugins).
<body>
<a href="#main-content">Skip to main content</a>
... 3 Menus, a search bar, etc.
<main id="main-content" tabindex="-1">
<h1>Heading</h1>
<p>This is the first paragraph</p>
</main>
</body>Actionable Elements
Any element on the page that you can interact with using the mouse must support keyboard interactions as well. Buttons, links, inputs, etc. Typically, these elements will be designed with mouse users in mind, with on-hover styles, bright colors or box shadows or blinking cursors to indicate potential actionable elements. Keep in mind that keyboard users need to know where their current focus is. That normally means using the same styles for the focus state and the hover state.
It’s also important to make the state of toggle-action elements clear to non-visual users. ARIA attributes that describe the state of actionable elements — including aria-expanded, aria-hidden, aria-pressed, aria-selected, and aria-haspopup — must be kept in sync as the user interacts with them. Most are boolean ("true"/"false"), but aria-haspopup takes a token value ("menu", "listbox", "tree", "grid", "dialog", "true", "false") describing the kind of popup being opened.
function expand(trigger, menu) {
trigger.setAttribute("aria-expanded", "true");
menu.removeAttribute("hidden");
}
function collapse(trigger, menu) {
trigger.setAttribute("aria-expanded", "false");
menu.setAttribute("hidden", "");
}Prefer the native hidden attribute over aria-hidden="true" when an element should be removed from both visual rendering and the accessibility tree. aria-hidden only hides from assistive tech and is easy to misuse.
Events
Events on the web page serve to increase dynamic behavior of web pages. Dynamic behavior does not always translate well to assistive technology because the behavior is often visual and driven by mouse activity, or events. Avoid relying only on mouse events like mouseover and click to fire JavaScript functions. Bind equivalent keyboard events to those functions, such as focus and keypress, to make JS functionality available to users without a mouse.
Most major browsers and assistive technologies bridge the potential accessibility gap caused by onClick events by also triggering their callback on spacebar and enter key presses. While helpful, this does not work in every single case, especially on elements like text, divs or table cells that are not typically actionable. Even when given an tabindex attribute or explicitly given focus by a script. This is why we expect to also need to bind keyboard and focus activity alongside mouse and hover.
The onDblClick event handler is associated with the double click of a mouse on a selected HTML element. There is no device independent or keyboard equivalent to onDblClick, so it must be avoided.
Do not use the JavaScript pseudo-protocol to trigger JavaScript events. And per our JavaScript standards, use data-* attributes as selectors.
Bad:
<div onclick="JavaScript:myFunction()">Open Menu</div>Good:
HTML
<button data-component="click-me">Open Menu</button>JavaScript
const trigger = document.querySelector('[data-component="click-me"]');
trigger.addEventListener("click", handleOpen);When using a true <button>, you get keyboard activation (Enter and Space) for free — no separate keypress handler needed. The need for paired mouse/keyboard handlers usually only arises when a non-button element has been pressed into service as an interactive control, which itself is a smell worth fixing.
Buttons
Buttons should be made with the native HTML <button> tag, and not a clickable image, or any other workaround that causes unnecessary confusion for screen-reader users.
Use buttons with type="submit" to designate the end of a form. Developers sometimes disable these buttons until the form has been adequately filled out, but doing so removes the only indicator that screen-reader users have that the form is ending. Do not do this.
Links
To make links accessible, they need to have text-based information that clearly describes their destination. The screen-reader does not announce the link path, so the inner text of the link element should be clear about where the link will take the user.
Bad:
<a href="/recipes/all">More</a>Good:
<a href="/recipes/all">All Recipes</a>It’s important not to use redundant language like “Link to…” or “Go to…” (the screen reader already declares that it has found a navigation element), or misleading text like “Click here” (implying the user needs to click rather than keyboard navigate).
Like all other text, avoid all-capitalize text content, as the screen reader will read text like letter by letter and is more difficult to read. Style text that must appear as capitalized with CSS’s text-transform property, but type it regularly in the HTML.
Avoid including the URL in the link text, as the format of web links will be read letter-by-letter and be extremely difficult to understand.
Style link text with some property besides color to increase visibility for low-vision, or color blind users. An underline is typically sufficient.
Imagery
Image-based content and information play a prominent role in the modern web. The accessibility standard expectations are very clear in their expectations for how this information should be delivered to screen-reader users: always provide equivalent alternative text-based sources of the information conveyed.
An important task for the developer is to identify all sources of visual information, and ensure that the alternative text-based information conveys all of the same information as the image.
Color, Shape, Location
Color is a major factor in WCAG conformance. Low-vision users need proper color contrast. Color-blind users will be unable to access information conveyed through certain color schemes. A required form field where the requirement is conveyed only through a red border is insufficient. See the sections on required fields and error reporting for more information.
Shape and location are sometimes used to guide a visual user’s attention on a web page. This is an acceptable practice, so long as those same visual cues are translated in some for screen-reader users.
Bad:
<p>Click the round button for True or the red button for False.</p>
<button class="btn-round">Button A</button>
<button class="btn-red">Button B</button>Good:
<p>Click the round button for True or the red button for False.</p>
<button class="btn-round">Round Button</button>
<button class="btn-red">Red Button</button>Similarly, a reference to location or relative position is not enough information for screen-readers. Do not reference visual location in instructional text—words like “left”, “right”, “top”, and “bottom” are not helpful to users with screen readers. Instead, use more concrete positioning language like “after the last section” or “at the end of the form.”
Bad:
<p>Click the bottom button to continue.</p>
<section>Example section</section>
<button class="btn-red">Button</button>Good:
<p>Click the button after the last section to continue.</p>
<section>Example section</section>
<button class="btn-red">Button</button>Images
When using images on the web, we need to keep in mind that they cause immediate accessibility pain points for non-visual and low-visual users. All information conveyed or functionality provided through images needs to be offered in the form of text alternatives.
Alt Attribute
The alt attribute on image content is required (per WCAG SC 1.1.1) for providing text alternatives for non-text content. This is necessary because most tools used to translate web content into other consumable forms rely on text-based information.
Rather than a description of the image itself, the alt attribute provides a description of the purpose of the image; what information it provides to a user who can see it, hover over it with the mouse, etc. For example, an image used as a navigation link must provide an alt attribute value that describes the destination of the link.
Bad:
<a href="#home">
<img src="ThinkCompanyLogo.png" alt="Image of thought bubble company logo" />
</a>Good:
<a href="#home">
<img src="ThinkCompanyLogo.png" alt="thinkcompany.com homepage" />
</a>Some specific things to make note of when using the alt attribute.
Describe the purpose of the image, rather than the image itself.
Include text included in the image in the alt attribute text.
A complex graphic, such as a flow chart or graph, will sometimes be accompanied by a real-text description nearby in the HTML markup. If that is the case, make sure the entirety of the information in the picture is provided in the accompanying text and provide an empty string for the alt value
alt="". Otherwise, included supplemental or summarization information in the alt text attribute.Include the alt attribute with an empty string value for images that are included more as “chrome” or decoration and don’t provide information.
Avoid starting with “Image of…” or equivalent phrases. Redundancy like this can cause confusion for users relying on screen-readers.
Don’t use line breaks in alt attributes, it can interfere with the proper functioning of screen-readers.
Forms
Forms are composed of controls (input, select, textarea), and descriptions/labels of the controls. An accessible form provides a logical, easy to follow user flow which requires grouping of thematically related controls, and associated labels for every individual control or group.
Labels
As stated in the overview, labels are important to guiding users through a form. Each form control must be accompanied by a descriptive <label>, and each <fieldset> must include a description of the grouping in a <legend> tag. Placeholder attributes are not sufficient substitutes for labels. screen-readers depend on an explicit label in nearly all cases.
Bad:
<input type="text" placeholder="First Name" />
<input type="text" placeholder="Last Name" />Good:
<label for="first-name">First Name</label>
<input id="first-name" type="text" placeholder="Tom..." />
<label for="last-name">Last Name</label>
<input id="last-name" type="text" placeholder="Brady..." />Radio Buttons and Checkboxes
Radio buttons and checkboxes are typically thematically grouped, and as such should be nested within a fieldset group. The group needs a descriptive legend.
Bad:
<label for="fav-food">Favorite Food</label>
<label for="avocado"> Avocado Ice Cream </labeL>
<input id="avocado" type="radio">
<label for="nightshades">Nightshades </labeL>
<input id="nightshades" type="radio">Good:
<fieldset>
<legend>Favorite Foods</legend>
<label for="avocado-ice-cream">Avocado Ice Cream</label>
<input id="avocado-ice-cream" type="radio" />
<label for="nightshades">Nightshades</label>
<input id="nightshades" type="radio" />
</fieldset>Select
Select menus must be accompanied by a label tag, similar to a simple input. <optgroup> tags can be used like fieldsets to organize and group thematically related <option>s, which will help improve the overall simplicity of form-flow.
<label for="movies">Movies</label>
<select id="movies">
<optgroup label="Comedy">
<option value="1">Superbad</option>
<option value="5">Shaun of the Dead</option>
<option value="7">Zoolander</option>
</optgroup>
<optgroup label="Horror">
<option value="3">Alien</option>
<option value="4">Saw II</option>
<option value="8">28 Days Later</option>
</optgroup>
</select>Instructional Form Text
There are additional ways that the details/restrictions of a form can be indicated to the user.
A list of rules about input format, password requirements, required inputs and other rules might be made explicit in a list preceding the entire form.
Alternatively, the label might include information for a specific form control:
<label for="pw">Password (min. 8 characters)</label
><input type="password" id="pw" />A third method that can be used to include instructional information from outside of the label. When using this method, we need the aria-describedby attribute to make explicit the relationship between the instructions and the control.
<label for="birthday">Expiration date:</label>
<input type="text" id="birthday" aria-describedby="date-format" />
<span id="date-format">MM/YYYY</span>Required Fields
It is common to denote required fields with a different color, asterisk, or other visual treatments, but this is insufficient for non-sighted users and those with color blindness.
Use the native HTML required attribute as the source of truth — it is well-supported by current screen readers (NVDA, JAWS, VoiceOver, TalkBack) and gives you free browser-level validation. Style the requirement marker visually in CSS or in the label text. Adding aria-required="true" is redundant when required is present; only use aria-required on custom widgets that cannot use the native attribute.
Examples:
HTML
<label for="name" class="required-field">Your Name</label>
<input type="text" id="name" name="name" required />CSS
.required-field::after {
content: " *";
color: var(--color-error);
}Disabled Form Elements
Buttons and form elements that are disabled but still in view must be assigned the disabled attribute (this is a boolean attribute and takes no assignment).
Convention regarding disabled elements is to present them as dimmed or grayed out, or otherwise different in appearance to indicate a disabled state. Disabled elements match the :disabled pseudo-class for styling purposes. Dimmed/grayed out elements don’t need to satisfy color contrast requirements. Disabled elements will not be able to be: clicked, edited, focused, or tabbed onto.
Example
<input type="text" id="shipping-address" disabled />Disabling Submit Buttons
It is not best practice to disable a submit button. Since disabled form elements must be removed from the tab order and must not be focusable, disabling a submit button can lead to confusion for someone using a screen-reader: there would be no indication to them that the form was concluded.
Validation
Validation is the process of conveying to the user interfacing with inputs that the format of their input needs to be edited in some way to be accepted. The first step to accessible validation is to utilize labels and additional instructional text to the extent that the user is clear on expected requirements/formats. We want actual form validation to be the safety net, not the only guideline.
Validation timing
Validate at the right moment, not just at submit. Both WCAG 2.2 (SC 3.3.1, 3.3.3, 3.3.4) and current user research support a layered approach:
- On submit (mandatory): Run a full validation pass; if errors exist, move focus to the first invalid field, summarize errors in an accessible region, and announce.
- On blur (recommended for non-empty fields): Once a user has finished entering data and moved away, validating that field’s format (e.g. “this isn’t a valid email”) is helpful, not harmful — provided the announcement uses an
aria-liveregion and the error message is associated with the field viaaria-describedby. - On input (use sparingly): Showing errors as the user types is generally disruptive. Showing positive feedback as criteria are met (a password strength meter announcing “meets length requirement”) is acceptable when implemented carefully.
The old advice of “validate only on submit” was a reaction to inaccessible 2010-era patterns. Modern screen readers handle live regions reliably; the rule is now “announce changes accessibly,” not “don’t announce changes.”
Let the user browse the form before validating the fields
Empty fields should remain valid as the user tabs through the form. Only generate an inline error on blur when the user has actually entered something invalid. Never generate an error simply because focus moved past an unfilled field.
Error Handling
Error handling is a huge accessibility issue on the web. Without careful markup a blind or visually-impaired user will be unable to figure out why (or even that) their form submission didn’t complete successfully. Avoiding the issues detailed about just-in-time validation, strictly adhere to the following strategy.
- Let the user know that there are errors on the page.
- Let the user know what the error is.
- Let the user know how many errors are on the page.
Let the user know that there are errors on the page. Upon validation:
- Move focus immediately to the first form element that contains an error.
- Set
aria-invalid="true"on each offending form field. Remove it (or set to"false") when the field becomes valid again.
Example:
<input id="date" type="text" aria-invalid="true" />Let the user know what the error is. Use the form field’s aria-describedby attribute to tie it to the error message. When the offending field receives focus, the error message will be announced. Do not assign multiple labels to the same input field to handle error text.
Example:
<label for="name">Your Name</label>
<input
type="text"
id="name"
aria-invalid="true"
aria-describedby="name-error"
/>
<p id="name-error">Please only use letters.</p>Let the user know how many errors are on the page. Preface each error message with its error number relative to the total number of errors, or surface a summary in an aria-live="polite" region at the top of the form.
Example (Best):
<label for="date">Date of Birth</label>
<input
type="text"
id="date"
aria-invalid="true"
aria-describedby="date-error"
/>
<p id="date-error">Error 2 of 2: please enter a valid date.</p>Tables
Screen readers are capable of navigating data tables that are marked up using the proper accessibility attributes and tags. The relevant constructs are:
<caption>: an element that contains a text description of the data in the table. This element renders by default, typically as left-justified text inside the boundaries of the table. It can be shifted off-screen via CSS if a visible caption isn’t part of the design.scope: attribute that appears on<th>cells to associate them with a row or column. Usescope="col"on header cells in<thead>. Usescope="row"on<th>cells that head each row in<tbody>. These do not render.
The HTML summary attribute on <table> is obsolete in HTML. For an extended description that doesn’t belong in the caption, use an adjacent paragraph and link to it with aria-describedby on the table.
Example:
<table aria-describedby="char-table-desc">
<caption>
Unicode Entities for Common Special Characters
</caption>
<thead>
<tr>
<th scope="col">Character</th>
<th scope="col">Entity Code</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Em Dash</th>
<td>—</td>
</tr>
<tr>
<th scope="row">Registered Trademark</th>
<td>™</td>
</tr>
</tbody>
</table>
<p id="char-table-desc">
Unicode entity codes used to render common special characters in HTML.
</p>More complex tables will require the use of headers and id attributes to associate data cells with multiple header cells.
iFrames
iFrames do not have full support from screen-readers and other assistive technologies. In general, avoid iFrames for complex content.
For simple content, they can be acceptable. They fall under the same category as other non-text content, like images, and require equivalent text alternatives. On iframes, that typically comes in the form of a title attribute on the <iframe> element.
Source Order vs. Visual Order
Flexbox and CSS Grid are essential layout tools and should be used freely. The accessibility concern they raise is not about the tools themselves, but about a long-standing rule: screen readers and keyboard tab order follow source order in the DOM, not the visual order produced by CSS. WCAG 2.2 SC 1.3.2 (Meaningful Sequence) requires that the reading order match the visual order whenever the visual order conveys meaning.
The properties that decouple visual order from source order are:
flex-direction: row-reverse/column-reverseorderon flex or grid itemsgrid-template-areasand explicit row/column placementflex-flow: wrap-reverse
Use them only when the reordered sequence still makes sense when read in source order. The right fix when source and visual order diverge is almost always to change the HTML source order, not to compensate with tabindex.
Do not use positive tabindex values (tabindex="1", tabindex="2", etc.) to “patch” tab order. Positive values pull elements out of the natural tab sequence and create maintenance nightmares — they are universally listed as an anti-pattern. The only valid tabindex values in production are 0 (make this element focusable in natural order) and -1 (make this element focusable only programmatically).
/* Risky — visual order no longer matches source order. */
.layout {
display: flex;
flex-direction: column-reverse;
}<!-- Better — reorder the source so visual and reading order match. -->
<div class="layout">
<header>...</header>
<main>...</main>
<footer>...</footer>
</div>Also avoid referring to the visual position of elements in instructional copy (“click the button on the right”). Position can change at smaller viewports or under user style overrides. Use the element’s name or function instead.
Accessible Email Requirements
Most email accessibility standards would automatically be covered by Web Accessibility Standards. Yet, there are some important differences between the two. Those differences are covered below.
Multiple Versions
Use a multi-part MIME to send a plain-text version along with the HTML version. Do not use rich text in the plain-text version.
Whenever possible, offer a link to a web version of your HTML email. The web version must follow the Web Accessibility Standards which are more rigid than these email rules. (i.e. using relative font sizing)
Subject
Always use a descriptive subject line for the email.
Reading Order
Make sure your reading order is logical and the HTML follows the visual layout.
Tab Order
Make sure your tab order is also logical, sequential, and follows the visual layout.
Fonts
Choose a typeface that reads well at small sizes and renders in the email clients you support. Sans-serif typefaces tend to perform better on low-resolution screens, but this is a design choice, not an accessibility requirement.
Do not set body text smaller than 16px. Do not set “small print” (footers, copyrights, T&Cs) smaller than 14px. On mobile (≤ 600px), body text should not drop below 16px.
Email clients have limited support for relative units. Pixels are usually unavoidable, but use rems/ems where the client supports them. Web alternative versions of the email must use relative font sizing.
Contrast
Identical to the web, text (be it HTML text or text in an image) must have a minimum contrast ratio of at least 4.5:1 unless:
- It is large-scale or bold text. Large scale/bold text ratio must be at least 3:1
- It is inactive (i.e. a disabled button) or decorative
- It is part of a logo or brand.
Beware of:
- defining a color that’s positioned in front of an image. Remember that images often don’t render in an email client unless you opt in. That text must also pass against the background if the image is turned off.
- photographic or variegated backgrounds. Test color contrast at the point of minimum contrast difference.
- text inside of an image. Image text must also pass minimum standards. You can use the following site to check color contrast for WCAG AA compliance: http://webaim.org/resources/contrastchecker/
Alt Text
All image tags must have a descriptive alt attribute. Do not use null alt attributes for email. If an image has text on the graphic, the alt attribute must be verbatim to the text on the graphic.
HTML Text
Favor HTML over text images for the majority of the email. Do not begin the content of the email below “the fold”. If there is only an image above “the fold” and the image(s) fail to render, the recipient will see large empty areas, rather than content which may be confusing to some people.
Text Alignment
Left align text. Stay away from centered or right-aligned text. Do not use justified text which can cause white spaces between words and letters. These “rivers of white” can be especially problematic for those with dyslexia.
Paragraphs
Use correct paragraph markup when creating blocks of text. Wrap paragraphs in the <p> element rather than simply adding text to table cells. Do not simulate paragraphs with line breaks (<br />).
Headings
All emails must contain one and only one <h1> tag.
All other heading tags must follow a logical sequence. For example, don’t jump to an <h3> after an <h1>.
Do not assign a heading tag to content that is not a true heading or subheading. Large bold text does not necessarily equate to a heading. Think semantically.
Links
All links must contain meaningful content. Do not use link text such as “click here” or “edit”. As on the web, this would create confusion for a person who brings up a links list or who navigates quickly by links.
Visual Focus State
Any time an actionable item is in focus it must show that focus, usually with an outline. Do not turn visual focus cues off. Make sure the focus state is not too subtle.
Target Size
Make sure your buttons and other actionable elements are large enough and include an inactive space around the target.
Per WCAG 2.2 SC 2.5.8 (Target Size — Minimum), the minimum target size is 24×24 CSS pixels. WCAG 2.1 SC 2.5.5 (Target Size — Enhanced, Level AAA) raises this to 44×44 CSS pixels for AAA conformance, which is what most modern design systems target.
Tables
Table layout is necessary in emails due to Outlook’s rendering engine. Therefore follow these rules when using tables for layout:
- Use tables only when absolutely necessary. Try not to use tables for the entire email.
- Only use the
<table>,<tr>, and<td>tags. Do not use<tbody>,<th>,<col>, etc. - Assign the role=“presentation” attribute to the table tag. This prevents the table semantics from being read out to the screen reader when used for layout. It will need to be repeated for nested tables.
- Do not use tables to format signatures.
- Use relative widths for table and table cell.
Mobile and Media Queries
Use media queries for screens <= 600px and apply the following styles:
Text for mobile <= 600px must be at least 16px. The “small print” for mobile must be at least 14px.
