An Introduction to Web Accessibility

If you're looking for a comprehensive introduction to web accessibility, this article is for you. I'll introduce web accessibility, how it is measured by the WCAG and simple but impactful changes you can make to your sites today to make them more accessible.


Web accessibility is design that works for everyone, regardless of the hardware and software they use to access your site. This involves understanding your fellow web users to anticipate their needs and how they consume information to build better experiences.

Here are some videos on the variety of software and hardware people use to surf the web. I recommend watching these videos, as they provide additional context and motivation for the rest of the article.

  • A screen reader user1: I recommend turning on captions for this video. Screen reader software reads on-screen information, and provides many keyboard shortcuts to speak information on demand such as what the next heading is, the url of the current page or the current paragraph. By relying on these keyboard shortcuts and the spoken output, users can operate a computer or mobile device without reading text or looking at the screen. This is helpful for users who are dyslexic or visually impaired.
  • A screen magnification user: screen magnification software makes it easier to read the screen by enlarging text, providing colour adjustments to increase contrast and making the cursor's location easier to find.
  • A voice input user: voice input software listens for spoken commands so that users can operate a computer by voice without the need for other physical movements.
  • An assistive switch user: assistive switches allow use of simpler physical movements like pressing a button or moving a joystick. These switches can be used to control a wide variety of devices such as computers and mobile phones.

Accessible websites increase useability for everyone.

  • Captions on a video helps anyone who isn't able to understand or hear the audio. For example, watching a video on a noisy train, foreign language movies or for someone who is hearing impaired. Captions can also be indexed by search engines, which is incredibly helpful for lectures, presentations and speeches.
  • Forms that are keyboard compatible, labelled correctly and built with HTML5 input features allow screen reader and password manager users to more accurately fill out the form. It is also faster to fill these forms via keyboard than the mouse by using the tab key to move between fields, space to toggle check boxes and enter to submit.
  • Using semantic HTML, choosing the right element for the content, makes it easier to programatically understand your site. Screen reader users can immediately move to the main contents of the page if it is under an <h1> or inside a <main> element. Search engines rely on logical heading structure to understand content. It future proofs your sites so that they work with future interfaces or devices.
  • Responsive design makes it easier for magnification software users as well as anyone on a mobile device to use the site.
  • Accessibility is a legal requirement in some countries. This should never be your main reason for implementing web accessibility. Nonetheless, it is important to highlight that it reduces your organization's legal risk.

Measuring Web Accessibility

The Web Content Accessibility Guidelines (WCAG are a systematic means of ensuring your website is accessible. It is also the standard used in many organizations, and is the basis of accessibility legislation.

There are 2 versions of the WCAG that are widely used: 2.0 and 2.1. WCAG 2.1 introduces additional success criteria and is backwards compatible with WCAG 2.0. Thus, using WCAG 2.1 for new content is recommended.

WCAG 2.1 consists of 13 guidelines, founded on the following POUR principles:

  1. Perceivable - information and UI elements are presented to users in ways they can perceive. Examples include alt text in images and captions in videos.
  2. Operable - UI elements must be operable by users, and shouldn't require interactions that users can't perform. For example, keyboard compatibility for users who are not using the mouse.
  3. Understandable - information and the operation of the UI must be understandable. For example, using clear language in text content, and descriptive error messages to make it easier to correct forms.
  4. Robust - content should be robust enough to be reliably interpreted by different browsers, assistive technologies and other user agents. This also means compatibility with future devices and interfaces which may not exist today. For example, using valid HTML so that it can be reliably interpreted.

Choosing a Level of Conformance

Each WCAG guideline contains testable success criteria which can be used to audit for conformance. For each success criteria, a website passes by implementing it correctly, and fails otherwise. There are 3 conformance levels, which represent things that you must do, should do or could do:

  • Level A: this is the minimum level of conformance. This is achieved when all level A success criteria are satisfied. If a website is not conformant to level A, there are significant barriers that prevent some users from being able to access content, and these issues are difficult or impossible to work around. A user using only the keyboard cannot activate drop down menus that only appear on mouse hover. A blind screen reader user cannot understand an image without an alternative description.
  • Level AA: this is achieved when all level A and level AA success criteria are satisfied. If a website is not conformant to level AA, there are issues that make it difficult for some users to access or use the content, though they could be worked around with effort. For example, not being able to follow focus due to missing focus outlines when navigating with a keyboard makes it difficult to use the site.
  • Level AAA: all level A, AA and AAA success criteria are satisfied. If a website is not conformant to level AAA, content is technically accessible, but there are issues that could be addressed to improve usability for everyone. For example, not explaining an acronym or abbreviation makes the content harder for everyone to understand.

Level AA is the generally accepted level of compliance that websites should attain.

Websites should comply to as many AAA success criteria as they can, but full AAA conformance is impossible for many sites. For example, replacing advanced terminology or jargon with simpler language for a website on web development to conform to success criteria 3.1.5 would make it unuseable by the intended audience.

Getting Started

The rest of this article introduces some simple things you can do to make your websites more accessible.

This is most effective when done for new functionality during development before it goes out for code review. It is easiest to fix problems at this stage of the development cycle, as they are addressed before it affects users.

You can also check existing content to ensure they implement the following best practices.

The techniques discussed here predate the rise of React and other frontend libraries, and are relevant regardless of what technologies are used.

Use Semantic HTML

Semantic HTML is the use of HTML elements according to what they are, instead of how they render in browsers by default. This enriches web content with meaning.

For instance, the heading tags <h1> through <h6> indicates the enclosed text is a heading, and the heading level communicates the hierarchical structure of the contents of the page. This is semantic because browsers know how to render them and presentational because readers know what headings are. On the other hand, the <b> tag is only presentational because it defines how text should look, but does not convey additional meaning.

Semantic HTML is the foundation of an accessible website. For example, screen readers provide alternative ways of navigating the page, so users can jump between different types of content like links, forms, headings, lists, and paragraphs. This wouldn't work if divs and spans were used instead, as they are explicitly designed to not convey any meaning.

Using semantic HTML is also a software engineering best practice. It makes development easier by resulting in more readable source, leveraging built-in functionality browsers provide for many elements and simplifying selectors.

Expertise in the correct use of HTML are often not valued or appreciated. Even though HTML is the building blocks of the web, many introductory online materials and university courses don't spend enough time teaching it in detail. Instead, they promote the misuse of divs and spans, attaching classes like button for styling and adding JavaScript to mimic the functionality of built-in elements. This is the root cause of many inaccessible websites.

Use Native HTML Whenever Possible

Use built-in HTML elements such as <a>, <button> and <select> for interactivity. This increases accessibility and leverages the built-in behaviour provided by browsers. Try navigating with a keyboard on this example webpage with some buttons, a select and some form fields.

  • A <button> is keyboard accessible by default. It can be reached by using the tab and shift+tab keys to move about the page and has an outline to indicate when focus lands on it. Its onClick handler is invoked by using the enter or space keys2. <button> is also correctly read as a button by screen readers.
  • A <select> is also keyboard accessible by default. When focused, the up / down arrow keys can be used to change the selected item.
  • The <datalist> provides autocomplete functionality when used with the <input> element. Autocomplete suggestions are presented while typing. The arrow and enter keys can be used to select the desired option. No JavaScript is needed for this behaviour.
  • Using the correct type of the <input> element allows mobile browsers to display specialized keyboards to make data entry easier. For example, typing into a <input type="email"> displays a keyboard optimized for email entry by showing an @ key.
  • <details> and <summary> are native elements for implementing disclosures, which are useful for showing additional information on request. They are accessible out of the box, and don't require any JavaScript.

Many sites use scripted divs and spans to replicate the functionality of native HTML elements. Unfortunately, they typically only account for use with a mouse and such controls are almost always inaccessible. While it is possible to do so correctly, it is easier to use normal HTML. See this example on replicating a button with a div for why this should be avoided.

Note that using scripted divs is not always bad - doing so is necessary when implementing widgets not built into HTML.

Use Headings to Create Logical Structure

Headings should be used to create a logical outline of the page. Good heading structure makes it easier for search engines and screen reader users to understand a web page.

The content under a <h1> should represent the main content of the page, subsections marked with <h2>, subsubsections with <h3> and so on. A heading's level should never increase by more than 1. For example, using a <h2> followed by an <h4>. The subsections of this article are also marked with various heading tags, which is used to automatically generate the table of contents.

You can use the a11y-outline extension to visualize the heading structure of a web page.

Watch out for these antipatterns:

  • Use of heading tags for formatting. It is very common for websites to use e.g a <h4> just for how it is styled in browsers even though the enclosed text is not logically a level 4 heading.
  • Pseudo-headings that can only be perceived visually. For example, use of a <b> or a <div> with CSS for section headings.

An <a> element without a valid href is not a valid hyperlink. Hence, browsers exclude them from tab order, making them inaccessible as they can't be activated via the keyboard. The default blue underline will also not be automatically applied for invalid links.

Code like <a onclick="...">my link</a> where script that performs the navigation is run on the onClick is very common, especially in Single Page Applications (SPAs). For example, try activating the links below with a keyboard by using tab or shift+tab to move focus, and enter to activate the link:

This is a link to Google with a valid Href.

This is an invalid link as it has no href attribute, and navigation happens via the onClick handler. Extra styling was used to replicate the usual appearance of a link. It can only be activated with a mouse.

This is usually caused by the following:

  • It can be difficult to decide when to use links or buttons. Use a <button> if an action is performed on click, but does not navigate you to a different page. Use an <a> to navigate to a section within the current page, or to a new page. Also avoid styling links to look like buttons and vice versa, as this causes confusion.
  • In SPAs, it is common for links to be rendered without a valid href,, with an onClick handler performing the actual navigation. If you see this in your own code, lean on routing in your application to use a proper href, and let browsers do what they are designed for - following links.

Invalid links without hrefs can still be made accessible by replicating the lost keyboard functionality that browsers provide, but this should only be a last resort:

  • Add tabIndex="0" so that the invalid link gets included in tab order.
  • Attach a keyboard handler so that the action performed on click is also triggered when pressing the enter key.

For more on using links effectively, see WebAIM's page on Links.

Programatically Label Form Elements

Associate labels with form elements like text fields, radio buttons, check boxes and buttons. This is usually done with the <label> element and the for attribute:

<label for="firstname">First name:</label>
<input type="text" name="firstname" id="firstname">

When a form field's purpose can be identified by visual cues so a visible label would be redundant, the aria-label attribute or a visually hidden <label> should be provided for screen reader and voice input users.

The <label> element can also be used as a container to label its form field:

  First name:
  <input type="text" name="firstname">

Browsers allow clicking the label to select its corresponding field, which is especially useful on mobile devices with smaller screens. Correctly labelling form elements provides a better experience for voice input users, so that commands like "click first name" work correctly. Labelling forms makes it much easier for password managers to autofill them accurately, since they don't have to resort to heuristics to figure out which field corresponds to which information is requested. Similarly, screen reader users also need to guess what label text is associated to which control when fields are not properly labelled.

Use the HTML5 Sectioning Elements

We use layout, spacing and colour to visually separate web pages into distinct sections such as a navigation bar, the main contents, supplementary asides and a footer with copyright information.

Replacing the use of the <div> container with semantic sectioning elements introduced in HTML 5 makes these relationships visible when not rendered visually. Screen readers present this information so their users can immediately comprehend the overall layout of the website, and move quickly to a particular section. Many other types of software rely on semantic sectioning elements to find and interpret the main contents of a page. Examples include search engines, read it later services like Pocket, Watch OS 5's display of web pages and the reader mode in browsers.

You can also use the a11y-outline extension to visualize the structure created by sectioning elements on a web page.

The most common sectioning elements include:

  • <header> typically for a section containing the website's main logo, title and navigation.
  • <nav> for sections of site-oriented navigation links. This may be nested in a <header>.
  • <main> for the section containing the main contents of the page. Avoid having more than one <main> element on a page.
  • <article> for self-contained content that would make sense outside the context of its surroundings.
  • <footer> usually for a page footer containing copyright and license information.

Here is how these elements would be used on a typical site.

  <!-- instead of using divs to contain each section, use the following instead -->
    <!-- logo, title etc -->
     <!-- navigation links here -->
    <!-- main site contents -->
    <!-- copyright and legal info -->

Use <table> For Tabular Content

Use the <table> element for tabular content. This makes it easier for software to interpret the data.

Screen readers rely on well structured tables heavily to provide a good reading experience. They provide specialized hotkeys for users to navigate by cell, move to the next or previous row and column, which mimics visually scanning horizontally or vertically. Using the <th> element for column headers causes announcements of the name of the column being moved to, which is equivalent to visually scanning upwards to check its title.

Avoid nesting tables within tables, as it is more difficult for software to parse and for users to understand.

Do not misuse <table> for visual layout. Use CSS instead because this is what CSS is designed for. Unfortunately, tables are often misused in emails for layout. This results in poor HTML which don't render well in some email clients. It also causes screen readers to attempt to interpret the entire email as a data table, making it challenging for their users to read such emails. Listen to the audio embeds on Litmus's blog post to experience how difficult it is to read emails with bad markup compared to one with clean HTML.

Besides tabular data, information that is spread across 2 axes should use the <table> element with styling to remove unwanted cell boarders if needed. The display of threads in a forum typically has the thread's title, its author, the number of posted replies and when the last reply was posted. If divs were used for each cell, it prevents efficient navigation scenarios for screen reader users like scanning downwards to rapidly see the titles of new threads or moving to the next column of information. To hear this with a screen reader, compare reading the statuses of pipelines being run on GitLab with reading the examples in the documentation for <table>3.

Test With a Keyboard

Test your website with a keyboard..

Keyboard accessibility is one of the most important aspects of web accessibility because many users rely on a keyboard. Filling out forms is often faster with a keyboard. Screen reader users typically interact with websites using the keyboard alone. Users who find it difficult to perform fine motor movements use the keyboard. Some users use voice input software or hardware like an assistive switch which mimics the functionality of a keyboard.

Use the tab and shift+tab keys to move between elements on the page, enter to activate controls and the arrow keys to move focus between elements in a composite widget like the nodes in a tree view4. Watch out for the following:

  • Is there always a focus outline that visually shows which element is currently receiving keyboard focus?
  • Does the order which elements get focus or focus order make sense? By default, focus order is the order which elements appear in the DOM.
  • When focus lands on an element or a widget, can it be fully interacted with via a keyboard? For example, buttons should be activated when pressing either space or enter. Using native HTML provides this functionality for free. For custom widgets, consult the Aria 1.1 Practices Guide for implementation guidance and expected keyboard behaviour.
  • Are there interactable elements that can't be reached via a keyboard?
  • If there are controls or information that are revealed on mouse hover, is there equivalent behaviour when the triggering element receives keyboard focus? Can newly revealed controls be tabbed to and activated?
  • When activating an element via the keyboard would cause it to be removed or moved to a different part of the DOM, does focus get moved to a logical location? For example, does activating the close button of a modal dialog restore focus to where it was before the modal was opened?
  • Are there keyboard equivalents for drag and drop operations?

Use Automated Testing To Catch Common Issues

Automated accessibility testing can highlight certain types of issues such as missing alt text in images, insufficient colour contrast, unlabelled form fields or incorrect heading structure. It is scalable, quick to run and can draw attention to problematic parts of a site.

However, automated testing can only discover up to 40% of accessibility issues. It is possible for a site to perfectly pass automated tests while actually being completely unuseable5. Automated testing also cannot assess the appropriateness of the alt text set on an image, find controls that only appear on mouse hover, flag a pseudo table built via divs that should be replaced with an actual <table> element or determine if a custom widget is actually easy to use in practice. Hence, it should be used together with actual manual tests.

There are many automated testing tools available. I recommend starting with the Axe extension or Lighthouse's accessibility audits. Lighthouse uses the Axe engine for accessibility auditing and is built into Chrome's dev tools.

Test With Actual Software And Users

To ensure your websites work well, test on various browsers, devices and assistive technologies. This will expose many problems that won't show up in automated tests.

Start first by testing with a keyboard, followed by a screen reader. Screen reader testing allows you to evaluate your websites from an entirely different perspective. Because of their use of semantic markup, testing with screen readers catches problems that would have been hard to spot visually. For instance, checking if reading order makes sense, labels on form elements, heading structure, table markup and assessing the accuracy of alt text in images.

If you've never used a screen reader before, it will be frustrating at first, and you may even mistakenly think your site is inaccessible because you aren't using it correctly. Here are some guides to using the NVDA screen reader on Windows, VoiceOver built into the Mac and screen readers built into iOS and Android devices. Note that with the exception of NVDA, the other screen readers are built in and don't need to be installed.

Include users of various types of software and hardware in usability testing. For example, users of screen readers, magnification software, voice input or a switch. This provide valuable feedback about how people actually use your site, and ensures it is not just accessible but easy to use for everyone.

Evaluate Accessibility of Third-Party Dependencies Before Use

When deciding whether to use a third-party dependency for a UI component, ensure that it is already accessible. This is critical because it is much harder to replace a dependency or try to fix it later, especially if it is a complex widget or is used for core functionality on your site.

Even if it claims to be accessible, actually do some testing yourself first to verify its accessibility. Consult the Aria 1.1 Practices Guide for expected behaviour. Ensure that they also meet this checklist of basic custom control requirements. Also apply this process on existing or new reuseable components in your application, since accessible components make it easier to build accessible applications.

Look through issues that other users of the library have reported. If reported accessibility issues are not addressed in a timely fashion, use a different one instead6.


Developing content that is universal to all users allows for more access, more exposure, and more dialogue. We should empathize with everyone who uses the internet, and we should design our web content to optimize for as much access as possible. The guidelines and examples above are just the first steps towards making this a reality.

Using semantic HTML is both an accessibility and software engineering best practice. It enriches web content with meaning, enabling the presentation of information in alternate formats to suit users, automated search engine crawlers and other programs. Using semantic HTML also avoids reimplementing built-in elements, an instance of code reuse and the "Don't repeat yourself" software engineering principle.

In the future, I will be writing in greater detail to explore topics such as applying these principles in the context of React applications, understanding the accessibility tree and building accessible custom widgets. Thank you for reading!


I'd love to hear from you. Please see the about page for ways you can reach me.


I'm very grateful to Joseph Goh, Ziwei Ang and my colleagues on the MyCareersFuture team at GovTech for the incredible support and insightful suggestions. I'd also like to thank Jordan Lee for his expert editorial support and writing advice.

  1. This is a recorded Smashing Magazine webinar that I highly recommend watching in full. The link above will start playing at the point where the screen reader usage demonstration starts. 

  2. Native HTML elements are keyboard compatible by default. Despite its name, the onClick handler is also invoked when such elements are keyboard activated. 

  3. Efficiently reading the list of pipelines being run on Gitlab with a screen reader is extremely inefficient due to the misuse of divs here. It is impossible to scan downwards to read the list of merge requests triggering pipelines or rapidly find pipelines that have failed. You might also notice many other issues on that page, but that isn't the main focus here. 

  4. When testing websites using a keyboard with Safari on the Mac, you must first enable the following setting: System Preferences > Keyboard > Shortcuts > Full Keyboard Access : All controls. I'm not sure why Apple disables this by default. 

  5. Granted, this is an extreme example, but the point stands. 

  6. This applies to all types of issues, not just accessibility related ones. If there are many open issues, then check that the library is at least updated regularly to fix the most important problems.