Accessible Checkboxes
This page shows different ways a checkbox can be marked up to see how screen readers will describe them to users.
A real styled HTML5 checkbox
<div>
tags.
Code Walkthrough of the Above Example
Below is the HTML of the above example. Use the dropdown to highlight each of the individual steps that makes the example accessible.
A DIV with a role of checkbox
If you come across a <div>
in existing code that is marked up like a checkbox,
you can fix it this way. It is preferable to use the HTML5 version instead, if you can implement
it quickly.
Code Walkthrough of the Above Example
Below is the HTML of the above example. Use the dropdown to highlight each of the individual steps that makes the example accessible.
HTML checkbox group
If you have a group of checkboxes, this is the proper way to style them. Instead of fieldsets,
you could use <role="group">
, which is described in the
ARIA form role example.
Code Walkthrough of the Above Example
Below is the HTML of the above example. Use the dropdown to highlight each of the individual steps that makes the example accessible.
Indeterminate Checkboxes Using Native HTML
We usually think of checkboxes being either checked or unchecked. There is a third possible state: indeterminate. The most common use-case for this, as outlined in the CSS Tricks article about Indeterminate Checkboxes, is for nested checkboxes. Consider you have a group of related attributes, like toppings in an ice-cream cone, that you can select with a group of checkboxes. It would be great to be able to have a "select all" checkbox that can choose all of them — because who doesn't want all the things on their ice-cream cone?!?! The problem is, what is this "select all" checkbox set to when some of the ingredients are checked but not all of them? While I have seen select all checkboxes not checked in this case, it can be argued that we give the indeterminate state for the checkbox.
Note that this indeterminate state can be set via JavaScript. There is no indeterminate
HTML attribute. It is set like this:
Note the last bit in the code above where we set the .checked
property to false
. This is done for progressive enhancement. While MDN reports that
indeterminate is supported in all major browsers, we should still consider that not all
browser/screen reader pairs (e.g. Firefox/NVDA, Firefox/Voiceover at the time of this writing) will announce the indeterminate
state. For this reason, we should set the checked attribute to something that makes sense for screen reader users who
use those browser/screen-reader pairs. Setting the checkbox to unchecked does make the most sense in this "Select
All" scenario.
Now that we got the basics out of the way, let's see an example of this in action:
This example uses a library we developed to set up the hierarchical structure for the select all button to work. Below are the developer notes on how the library does it. If you are interested in using the library, please read the instructions on how to use the library in your own projects.
Code Walkthrough of the Above Example
Below is the HTML of the above example. Use the dropdown to highlight each of the individual steps that makes the example accessible.
Indeterminate Checkboxes Using ARIA
Just like two-state checkboxes, we can use ARIA to create faux-checkboxes. At the time of this writing, there is one advantage of doing so: Firefox using Voiceover and NVDA will report an indeterminate checkbox's state as mixed using ARIA.
// Let's assumeThis example uses the same library we used in the native HTML5 example to set up the hierarchical structure for the select all button to work. As you compare the developer notes below to that of the HTML5 example, you will see the way to implement is similar. Please read the instructions on how to use the library in your own projects.
Code Walkthrough of the Above Example
Below is the HTML of the above example. Use the dropdown to highlight each of the individual steps that makes the example accessible.
How to Install the Hierarchical Checkbox library Into Your Projects
Installation Instructions
You can load this JavaScript library into your application in serveral ways:
- as an ES6 module using Webpack.
- as a CommonJS module using
require()
and Webpack. - as a native ES6 module within the browser.
- as an old-school ES4/JavaScript library.
If you haven't done so already, choosing which you should use is obviously a major architectural decision. Here are a few articles that will help you decide:
- Jan Olaf Krems gives a great overview of the JavaScript File Format Differences
- Joe Honton discusses that With ES Modules and HTTP/2 You May Not Need Webpack Anymore
- Stack Overflow has a really good thread about Webpack vs ES6 modules as well.
Using NPM/Webpack to load ES6 Modules:
-
Install the
enable-a11y
NPM project. -
Edit your webpack.config.json file to resolve the
~
modifier by adding the following:module.exports = { ... resolve: { extensions: ['.js', '.jsx', '.scss', '.css', '*.html'], modules: [ path.resolve('./src/js'), path.resolve('./node_modules') ], alias: { '~enable-a11y': path.resolve(__dirname, 'node_modules/enable-a11y') }, ... }, ... }
-
You can use the module like this:
// import the JS module import hierarchicalCheckboxes from '~enable-a11y/js/modules/hierarchical-checkboxes'; // How to initialize the hierarchicalCheckboxes library hierarchicalCheckboxes.init();
Using NPM/Webpack to Load Modules Using CommonJS Syntax
-
Install the
enable-a11y
NPM project. -
You can import the module using require like this:
var hierarchicalCheckboxes = require('enable-a11y/hierarchical-checkboxes').default; ... hierarchicalCheckboxes.init();
Using ES6 modules natively.
This is the method that this page you are reading now loads the scripts.
- Grab the source by either using NPM, grabbing a ZIP file or cloning the enable source code from github.
-
If you want to load the module as a native ES6 module, copy
js/modules/hierarchical-checkboxes.js
from the repo and put them in the appropriate directories in your project (all JS files must be in the same directory).
-
Load your scripts using the follwing code (NOTE: you must use
<script type="module">
):<script type="module"> import hierarchicalCheckboxes from "path-to/hierarchical-checkboxes.js" hierarchicalCheckboxes.init(); </script>
Using ES4
Just do the same as the ES6 method, except you should get the JavaScript files from thejs/modules/es4
directory instead of the js/modules/
:
<script src="path-to/es4/hierarchical-checkboxes.js"></script>