Develop Accessibly

Accessibility requirements relevant to front-end development cluster around issues of screen reader hinting, keyboard and mobile compatibility, and interactive and form controls.

Key concepts

  • Imitation is the sincerest form of flattery. Creating accessible forms and interactive elements is hard. Whenever possible, use accessible frameworks and design patterns.
  • Test as you work. Running quick automated and keyboard tests will naturally guide you into discovering and fixing many of the items on this page.
  • Know how screen readers read. Screen reader users skim headings, regions or links to indicate items of interest, and they expect to hear their readers always announce the name, role and value of components: "Visited [value] link [role]: headings, regions or links [name]."
  • Beware the :hover state:
    • Keyboard users use the Tab key (or the equivalent) to advance through links and interactive elements. They need :focus states on elements to see where their cursor is, keyboard click event handlers for custom buttons, and skip links to get past navigation.
    • Screen readers often do not trigger hover OR focus events. Screen readers in their default mode explore pages using a virtual cursor, and do not advance the "real" cursor unless the user clicks to interact. This is incompatible with some menu design patterns.
    • Automatically playing media can present significant obstacles to many users; screen readers cannot be heard over audio, and users with vestibular (motion sickness), reading, or attention disorders may have trouble interacting with text near animated elements.

    Developer's Guide

    Structuring the Page

    1. Help screen reader users skim:
      • Use clear and specific page titles.
      • Structure the page with HTML landmark regions (header, nav, main, footer).
      • Use headers to label key regions, such as the navigation, search and footer, as well as any alerts. These labels can be visually hidden.
      • Differentiate reusable landmarks like <nav> elements with headings or aria-labels: (the main "site" navigation, the vertical "section" navigation).
      • Make sure every focusable element contains accessible text or an aria label, especially icon buttons.
      • Use semantic elements (regions, lists, figures, tables, etc). They are understood and announced by screen readers, and many have special browsing modes (jump to next region/cell/list item/row); simple containers (<div>, <span>) do not provide any of this.
    2. Don't visually reorder elements and regions. Keyboards and assistive devices read the DOM order, and users expect that to match the visual reading order (left to right, top to bottom).
    3. Provide a "skip to main" link, and point it at a named anchor set to tabindex="-1". Targeting unfocusable elements may scroll them into view, but only focusable targets actually transfer focus for keyboard users!
    4. Validate your HTML.

    Responsive Breakpoints & Reflow

    1. Never disable viewport zoom.
    2. Refrain from limiting the height of text containers. Up to 3% of users have modified their default font or font size, which can cause unexpected overflows of fixed-size containers. At a minimum, try to size elements relative to the font size (em or rem) instead of using px units. 
    3. Make sure your code supports accessible design considerations for device flexibility regarding element scaling for small, large, low PPI and high PPI devices.
    4. Expect users to commonly have viewports as narrow as 320px and as wide as 2560px.
      • Make sure your code works in both portrait and landscape.
      • Do not assume users viewing your narrowest (mobile) breakpoint will not be using a keyboard and/or mouse. Their phone may be paired with an input device, or they may be on a desktop with a screen magnifier. Your mobile theme still needs :focus indicators and keyboard click handlers.
      • Do not assume users viewing your widest (desktop) breakpoint will not be using a touchscreen. Large tablets have viewports wider than 1280px. Your desktop theme still needs touch handlers and cannot rely on :hover.

    Forms

    1. Make sure every form element has an accessible label for screen readers, and can be operated by a keyboard.
    2. Identify errors specifically, and be sure to tag errors well for screen readers. Be as helpful as possible; e.g.,  "Please provide your birthday as YYYY-MM-DD," rather than "Invalid date format."
    3. If your form has a time limit of less than a day, make sure it can be extended or disabled, unless one of the exceptions in the "Enough Time" guideline applies.
    4. If your form handles legal commitments or financial transactions, be sure to read the detailed guidelines regarding user review, correction and confirmation.

    Consult the W3C Forms Tutorial for more depth and code samples.

    In detail: Interactive Components

    Modals, Slideshows, Menu Bars, Accordions, Tab Panels...every part of an interactive component, from its outer container to its buttons, status messages and focus transfers, needs to be accessible to keyboards and screen readers. Whenever possible, use pre-tested accessible frameworks or design patterns.

    Before creating your own interactive components, read the MDN WAI-ARIA basics.

    Some general tips:

    1. Every focusable element (links, buttons, fields and anything with a tabindex value of 0 or greater) must have a clear, visible visual indication of :focus.
    2. Make sure element triggers work with all input devices; elements sensitive to :hover (e.g. menu flyouts) should also react to :focus...and screen readers that cannot hover or focus should have some way to get to the same content.
    3. Manage keyboard focus in the same way you manage visual attention grabbing:
      • If a button launches a modal or overlay, set a short JavaScript timeout and then transfer keyboard focus to the first focusable element in the modal or overlay (the short delay makes sure the screen reader parses the new content, so that it notices and announces the context change).
      • If that element can be closed, transfer focus back to the button that launched it after it closes.
    4. If you plan to implement any custom event handling, first read the guidelines regarding multipoint or path-based gestures, motion actuation and down-event pointer cancellation.
    5. Character key shortcuts can conflict with many assistive devices; make sure any shortcuts can disabled or remapped, or are only affect particular focused components.
    6. Users can pause, stop or hide any non-essential motion that starts automatically and lasts more than 5 seconds.
    7. Shoehorning accessibility into custom elements is error-prone and time consuming. The native, semantic <button> does everything <div aria-role="button" aria-label="fake button" tabindex="0" onclick="clickHandler"> does, and also doesn't need additional JavaScript to handle Enter and Space keypresses.

    In detail: Hiding Elements

    There are five recommended design patterns for hiding elements, depending on who you want to hide the content from:

    1. The CSS clip pattern hides an element visually.
      • Used to visually hide items assistive devices should still be able to reach and read, such as assistive text or keyboard-only elements that will appear on :focus.
    2. An attribute of tabindex="-1" hides an element from the Tab key.
      • Used to remove default keyboard functionality from otherwise focusable elements, such as temporarily disabled parts of forms.
      • Interesting note: setting this on an element that is not normally focusable makes it possible for JavaScript to manually place focus on it without adding it to the tab order, e.g. when transferring focus to a heading. Quite useful; just don't put it on large containers (or remove it immediately after transferring focus), as clicking on an element with negative tabindex shifts focus back to that element's parent, which can be super confusing if, say, <main> has a negative tabindex and folks keep getting bounced back to the top of the page as they try to fill out a form.
    3. An attribute of aria-hidden="1" prevents a screen reader from reading any text in the marked element or its children.
      • Used to hide inaccessible pieces of elements with accessible alternatives, such as the icon inside a button with a separate, accessible label.
      • This attribute should never be given to a focusable element or an element with focusable children, as the screen reader will still be able reach the element, but will not be able to say anything when it gets there. Few things are more detrimental to a screen reader user than silence.
    4. Combining tabindex="-1" and aria-hidden="1" hides otherwise visible elements from screen readers and keyboard access, and removes them from screen reader element lists.
      • Used mark redundant visual elements as skippable by assistive devices, e.g., links that say "read more" in news cards with independently linked headlines.
    5. Setting an element to CSS display:none; or HTML hidden completely hides the element visually and from assistive devices.
      • Used for elements that should be completely unreachable at the moment and should not appear when focused, such as hidden panels in tabbed interfaces and accordions.
      • Important note: never use display:none on structural headers and page regions, as this removes these key elements from screen reader jump-to lists. If you want to hide key regions like site navigation or search until a toggle button is pressed, a good design pattern is to put the toggle buttons inside the <nav> and <search> regions, after the only-visually-hidden structural <h2> header, and only mark the actual search field or navigation list as display:none. This pattern makes it so screen readers always have "Navigation" and "Search" regions and headers available in their jump-to lists as shortcuts to the toggle buttons:
        <nav aria-label="site">
          <h2>Site Navigation</h2>
          <button>...</button>
          <ul style="display:none;">...

    Hiding Patterns Compared

    Method Visual State Keyboard State Screen Reader State
    CSS Clip Hidden Focusable Readable
    tabindex Visible Unfocusable Readable but unfocusable
    aria-hidden Visible Focusable Unreadable but focusable
    tabindex and aria-hidden Visible Unfocusable Hidden
    display:none Hidden Unfocusable Hidden

     A Quick Self-Led Training

    1. Explore the W3C Annotated Accessible Homepage, which provides annotated right/wrong examples, including code samples.
    2. Read our guide to DIY testing, and do some DIY tests on the W3C demo site:
      • Try to navigate the inaccessible and accessible versions with your keyboard. Note the dramatic differences in focus indication.
      • Explore the W3C demonstration again in the WebAIM Wave Tool, to practice doing your own automated testing.

    Further Reading and Online Classes