Jambo, I'm Julia.

Accessibility Tips For Web Development


8 min read

One of my knowledge gaps within web development that I really want to bridge is accessibility. In all of the apps / engineering teams I’ve worked on professionally to date, accessibility (unfortunately) has never played a front and centre stage, and tends to be more of an afterthought. This is mostly due to time and resource constraints, but also a lack of knowledge on how to implement accessible apps and the benefits it brings.

To start making steps to improve my knowledge, I recently decided to take an online course on accessibility for web development. Here are my quick notes and key takeaways, written in a cheat sheet format (mostly for me to reference back to at a later date!). If you’re knowledgeable about accessible web development, and think I’ve missed something crucial out, please do let me know, and I’ll add it to the list.

Screen readers

  • Add alt text to images, otherwise screen readers will end up reading the filename.
  • Empty strings as alt tags will cause the screen reader to skip over the image (which may be the desired effect you want, e.g. for user uploaded images or decorative images).
  • For complex images, you could make the image hidden to screen readers, but add some text below, that’s visually hidden, but readable by screen readers.
  • If you have a video, add captions. At WCAG2 Level A, you can include this as a transcript. To improve on this, use synchronised captions.
  • Screen readers ignore CSS background images.
<aside> 💡 In Mac OS, the screen reader can be activated via the VoiceOver settings.</aside>

Accessible HTML

  • Use appropriate semantic markup. Some have no special functionality, but others do, like button, input and textarea.
    • e.g. if you just use div, this would not be read by a screen reader.
  • Don’t choose which header tags to use based on formatting! e.g. there should only be one h1 tag per page.
  • Ensure that the reading and navigation order (determined by code order) is logical (so it makes sense when read by a screen reader from top to bottom).
  • Use form field labels, so that form inputs can be read by screen readers. Labels can be used explicitly (use for to link it to a particular input name) or implicitly (wraps the name and input field - does not need for attribute).
  • The label tag only works with certain elements (e.g. input, button).
    • If you need to label an element that’s not “label-able”, use aria-label attribute instead (however note that it would only work on focusable elements, so would also require a tabindex attribute).
  • Use a specific class to visually hide an element that’s solely for screen reader only content.
    .visuallyhidden {
      position: absolute;
      left: 0;
      top: -500px;
      width: 1px;
      height: 1px;
      overflow: hidden;
  • If you choose not to use the button element, and instead to use a div styled as a button, you’d also need to include the following attributes to make it accessible:
    • onclick=”xxx”
    • role=”button” (this is the ARIA role, used by screen readers)
    • tabindex=”0” (or whatever number, to make it tab-able and focusable with the keyboard)
    • onkeyup=”xxx” (to ensure keyboard-only users can interact with the button)

ARIA - Accessible Rich Internet Applications

  • Labels
    • aria-label - inline attribute
    • aria-labelledby - allows you to link to an element id that contains the text for the label e.g. could be handy for handling translations
    • aria-describedby - provides extended information the user might need
  • Roles can be applied to any element. Role examples include button, checkbox, tree, banner.
  • States and properties inform what the current state of an element / app is in e.g. is a checkbox checked, or is a form invalid? These would need to be added and removed in line with the user action.
  • You can use ARIA properties within CSS since they are just data selectors.
  • The ARIA spec allows us to mark an element as containing live data so that screen readers can read out live updates as they come.
    • assertive means interrupt, polite announces the update when the screen reader is next idle. off will not read the update.
    • This kicks in whenever the content between the div tag changes.
    <div aria-live="assertive">Waiting for a ride</div>

Focus management

  • Keyboard shortcuts - allow users to access different features through using the keyboard alone.
  • Keyboard only users - show focus rings around elements which are also safe for screen readers. Should be able to reach the next focusable element by tabbing.
    • Also should not result in a substantial change in the page layout e.g. page shifts because of the focus ring designs.
  • Skip links help users skip over large headers and navigation, to go straight to the main content of the site (without having to tab through each link).
    • Create an anchor within the body and add it to the start of your HTML content. Make it visually hidden, until someone hits tab (and make it immediately in focus).
    • The anchor should then link to the main content.
  • Accessible tab navigation allows a user to navigate to the next tabbable item. Shift + tab allows a user to navigate back.
    • Tabbable elements out of the box include: a, button, input, select, textarea, iframe
  • Use a tabindex attribute to make any element tabbable
    • A negative value means it should be focusable, but not reachable via sequential keyboard navigation.
    • 0 means the element should be focusable and reachable, but its relative order is defined by the platform convention.
    • A positive value means it should be focusable and reachable. Its relative order is defined by the value of the attribute. The higher the value, the earlier it’s reached.
  • Note, top level elements should be tabbable, but child elements should be arrow-key reachable e.g. if you have a tab navigation, with “more” as one of the tabs, the child links within “more” should not be accessed via the tab key, but arrow keys.
  • You can get the DOM’s current active element by using document.activeElement. This is useful to store the currently focused element before a page transition so you can return the user to it later.
  • Tab trapping is a JS technique where you grab the first and last element in a modal, and listen to keydown events for when the user is on the first/last element. You can then ensure that the tab and shift+tab takes the user through a loop of the tabbable elements in the modal (otherwise the user might tab out of the modal to the main document, even whilst the modal is open).

Visual considerations

  • Use this website to check colour contrast: https://webaim.org/resources/contrastchecker/
    • Lighthouse audit (Chrome extension) can also check your live site.
    • Chrome devtools’s colour picker shows the contrast ratio of two colours, however, this only works if you’ve set the child within a parent component (rather than against the document body).
  • You shouldn’t just rely on colour to relay feedback back to the user (e.g. with form validation). There should also be some other method of feedback, like text.
  • Consider using NoCoffee for Firefox to simulate what visual impairment views might look like.
  • Consider keeping related items (especially those that provide feedback to user interactions) close together to help users with limited field of vision.
  • Set the lang attribute (the language of your site) at the top of your HTML file (and any subsequent sections where the language deviates from the default).
  • Even though it might not be visually apparent, WCAG also specifies you should ensure your HTML is free of syntax and parsing errors.
  • Users can set a “prefers reduced motion” option on their operating system. This is important for users who may suffer from seizures.
    • This is accessible within CSS via an @media (prefers-reduced-motion) query.
  • Users can also set their system’s preferred colour scheme (i.e. light vs dark colour scheme).
    • This is accessible within CSS via an @media (prefers-color-scheme) query.


© 2016-2023 Julia Tan · Powered by Next JS.