The definition of accessibility is making something available to, and usable by, as many people as possible. Web accessibility specifically means making websites equally usable for people with disabilities. It’s the internet equivalent of wheelchair ramps, reserved parking spots, braille on signs, or subtitles on movies.
Web accessibility standards are defined by the Web Content Accessibility Guidelines (WCAG) — they are the global legal standard. There are 4 types of disabilities covered: hearing impairments, visual impairments, motor impairments, and cognitive disabilities.
Standards include being screen reader compatible for people who are blind or have low vision, allowing keyboard navigation for people with motor impairments, being seizure safe for people with epilepsy, and content being comprehensible for people with cognitive and learning disabilities.
On a practical level, having an accessible web page matters because you can get sued if you don’t. Americans with disabilities are protected under the Americans with Disabilities Act (ADA) — the Department of Justice considers websites “public accommodations” and they are held to the same legal accessibility standards as other public accommodations.
Public accommodations are any facility that is used by the public at large. They can be publicly or privately owned. Some examples are restaurants, retail stores, and athletic facilities. In 2022, over 8000 demand letters were sent to website owners under the ADA, and over 3250 lawsuits were filed.
More importantly, it’s the right thing to do. It is estimated that 20–25% of the general population have a disability. People with disabilities deserve access to the same services and perks everyone else does, and making sure your website is accessible helps create an equitable world.
Before you get started writing code that is accessible, there are aspects of the UI design that need to be taken into consideration. If you have a designer you work with, designing for accessibility would fall under their responsibilities. However, many front-end engineers — whether working freelance, or at small companies where employees may have many different responsibilities — also have some responsibility for UI design.
Two of the most important parts of designing for accessibility concern color. First of all, color contrast must be high enough even for people with low vision to be able to discern. Color contrast for text must be at a minimum of 4.5:1 for small text and 3:1 for large text. These contrast ratios range from 1:1 — white on white — to 21:1 — black on white. Many websites and browser extensions can check color contrast for you.
The other important design consideration regarding color is that color should never be the sole thing differentiating something. For instance, an error that is just a red border around an input instead of the default border, or if links are a different color but don’t have any other styling. Users who are colorblind are not able to discern color differences. A better design would be to include other differentiators, such as a warning icon or a message for an error, or the default underline styling for a link.
Forms are one of the trickiest parts of designing for accessibility. Several aspects of forms are important to keep in mind. First of all, every input should have a label. Placeholders are not replacements for labels for several reasons. First of all, they disappear when you start typing, so people with memory issues may have trouble. Second, placeholder text tends to be light gray on white, which is below the minimum contrast standard and difficult for people with visual impairments to see. Finally, if there are errors — for instance if a user leaves a field empty or fills it out with an incorrect format — rather than a general alert or banner, the focus should move to the input with the error, and it should be clear what it is (and, as mentioned above, there should be more than just a color change to signify it).
Links should be descriptive — rather than saying “Click here,” it should say “Click here to read more about Alaskan Malamutes.” For users using a screen reader, just hearing “Click here” is confusing. Links that go to external websites should indicate such — whether that is with an icon (like the typical box with an arrow), and visual or aria labels that say “This opens in a new window.” For the above example, the link would read “Click here to read more about Alaskan Malamutes” and then “opens in a new window” to be fully accessible.
Everything should have a visual label if it’s not clear what it is. Buttons, drop downs, inputs — everything needs a visual label so people with cognitive disabilities can also understand. For instance, rather than a button that is only an icon, it is better to have a visual label so people with cognitive disabilities can easily understand.
The bulk of writing accessible code falls under writing semantic HTML. This means, using descriptive html tags (<nav>, <main>, <footer>, <header>, <article>) rather than generic divs and spans. Screen readers will read the html to users, and hearing “article” or “navigation” communicates much more to the user than “div” or “span”. When specific tags aren’t available, you can use aria-role to communicate that information to users (ie, aria-role=checkbox, aria-role=navigation). Additionally, it’s important to use tags for their intended purpose — don’t switch <a> and <button> tags and just style them to look the way you want.
Header tags have specific guidelines — there should only be one h1 on a page, and any other header tags should be consecutive, so for instance, there should never be an h2 within an h3, and you should move from an h1 to an h4. If you want headers to look specific ways, use css styling to do that. This has to do with screen readers as well — a screen reader will read the users all h2s and allow users to jump between sections via the h2 headers, and if the headers are out of order, the screen reader cannot appropriately organize the page. When this happens, people with visual impairments cannot navigate the web page.
Tables should be built with table tags. They also should have a header set within the row, so that when the screenreader reads the table data to the user, it communicates to the user what row it is (ie, in a table of movies and their rankings and box office data, each row’s header would be the name of the movie).
Aria is short for “Accessible Rich Internet Applications”. Basically, they are a set of tags that help describe elements in a way that HTML may not be able to. For example, a modal can’t be created in a way that HTML can convey what it is, but if we add role=”alertdialog” aria-modal=”true”, a screen reader will be able to convey what’s happening to a user. We won’t go into all of the available tags here, but there are many cheat sheets available such as this one from DigitalA11y.
An aria-label is a label that is not visible on the page but will be read by the screen reader. Aria-labels can be added to anything and should be used in any instance where there is not a text label or when the text label may not provide enough information, such as the example with a link that opens in a new window. For instance, if there is a search bar that just has a magnifying glass icon to identify it, the aria-label should be set to “search” so visually impaired users know what the input does. Aria-labelledby
(used with the id of the element that has the label) can be used if the element with the label is not otherwise linked. For instance, if you use an h2 to label your “Search” input, you can use aria-labelledby
to refer to that h2, rather than the aria-label.
All images should have alt tags. Those tags should be descriptive, and should not include the word image, because screen readers already say “this is an image.” If an image is purely decorative and serves no function (for instance, if your search input has a label that includes both the word search and a magnifying glass icon, that icon is purely decorative), then there should still be an alt tag, but it should be set to an empty string (alt=””). If an image doesn’t have an alt tag, the screen reader will read the entire file name, which is not helpful to users. The empty string is what tells the screen reader to ignore an image.
Pages must be able to be navigated with the keyboard for users who have motor impairments that make using a mouse difficult. To navigate a page with a keyboard, all features that can be clicked have to be focusable, and they have to be within the tab index appropriately so that they will be focused in the correct order.
To preserve the tab index, buttons should not be disabled — a disabled button is removed from the tab index, which is confusing to users (“Why isn’t there a button on this form? How will I submit it?”). Aria-disabled will disable the button without taking it out of the tab index. Additionally, setting tabindex to 0 will put an item into the normal flow of a page. Setting a tabindex to -1 will remove it from the flow of a page (this can be helpful for purely decorative icons and other nonfunctional elements). In general, try not to change tabIndex too much unless something is explicitly broken or incorrect. Changing tab-index too much (and similarly z-index) can cause a rabbit hole of bugs.
When you’re setting font sizes, setting them with rem keeps the page accessible in a way pixels do not. Fonts set with rems will get larger if a user increases the default font size in their browser, but fonts set with pixels don’t. Users with visual impairments who need larger text sizes are going to have a much easier time when the website adapts with the default browser font size settings. Additionally, don’t use fonts that aren’t standard for general information. A simple font is much more visually accessible as well as cognitively accessible than a font with decoration.
If you’re using a shared component library, or an external library, and those components have accessibility props — always use them, even if they’re optional. They’re built in for a reason, and they are going to save you the work of manually managing accessibility yourself (or having inaccessible components because you can’t alter them).
While language isn’t part of the WCAG standards, more than half of the human population speaks multiple languages to some degree. It’s much easier to navigate a website in your native language than have to translate as you go with a language that you may not understand as well. This is where translators come in. There are many tools for this application, but one of the easiest implementations comes from FormatJS. Essentially, you wrap all strings within this library and the library will automatically translate to a variety of languages. This is a shockingly easy thing to implement which will allow many more users to use your application comfortably.
There are several tools out there to help developers test for the accessibility of their pages and apps; however, even the most thorough tools are estimated to catch only 40% of errors. Manual testing is the most important part of accessibility testing.
To test manually, first, tab through your page with a keyboard. Make sure everything that you can access with a mouse is also accessible via the keyboard.
Additionally, use your computer’s built-in screen reader to try and navigate your site. On Macs, the built-in screen reader is called VoiceOver, on Windows, it’s called Narrator.
While automated tests only catch 40% of accessibility issues, it’s better to catch them than miss them! There are a few types of automated accessibility tests you can set up in your project.
Linters check static code against set rules, and many organizations use them. In terms of accessibility, the types of static code issues that can be caught by linters include semantic HTML mistakes and alt-tag issues. There are several accessibility plugins for es-lint out there that will check your code for you. If your code is written in React, eslint-plugin-jsx-a11y
will work for you, eslint-plugin-vuejs-accessibility
works with Vue.js, and angular-eslint
works with Angular. However, using a design system like bootstrap will prevent a linter from catching all of the potential errors.
Unit and integration tests involve actually running the code, and these tests will be able to catch more issues than a linter will (especially if you’re using a design system — unit tests should allow you to catch those issues the linter couldn’t).
The company Deque provides multiple npm libraries that work with a variety of frontend and testing frameworks (including Jest, React with React Testing Library, React with Enzyme, Vue, Angular, Jasmine, Mocha, etc). These libraries run accessibility checks already defined in the library, so once the library is installed, all you have to do is call the test method from the library, and it runs all the tests for you. You do not have to manually create any accessibility tests.
Browser testing will actually render code in a browser, and evaluate what is rendered. Because of this, it can catch some errors that linters and unit tests can’t, like color contrast issues.
Like unit and integration tests, there are several libraries out there you can use with your browser testing setup so you don’t have to manually write tests yourself. For instance, if you are using Cypress, there is the cypress-audit/lighthouse package. Lighthouse-ci and pa11y-ci are CI libraries.
Additionally, Deque, who maintains axe libraries for unit tests mentioned in the last section, also has axe packages for Cypress, Selenium, and other browser testing frameworks.
Because of the variety of disabilities, there are a lot of different aspects to designing and building accessible websites, and it can be overwhelming to get started. Luckily, actually implementing accessible components is easy once you know what to do, and the number of testing libraries with accessibility test suites already written makes it even easier to build and maintain accessible code. A large proportion of the population — and your potential customers — have disabilities, and making sure everyone has access to your services helps build a more inclusive, equitable world.
Co-written by Danielle Ford and Allie Craig
DigitalA11y Aria Role Cheat Sheet
Udemy Course on React Accessibility Testing
Udemy Course on Accessible Design
Chrome Extension for Simulating Colorblindness
Axe Core testing integrations (for unit and browser testing)