Feature Spotlight: Accessibility
Accessibility! The most important feature you never knew about.
In the Video.js organization we try hard to have good accessibility. Like most other software, any change can affect the system in unintended ways. For example MuteToggle
and VolumeControl
were married into VolumeMenuButton
in Video.js 5. While this change did allow these controls to work in tandem visually, it also did something unintended. It broke accessibility. In this post we will go over what broke, what the fix was, what accessibility is, and how to test and make sure it works.
Feel free to skip to the last section if you already know what accessibility is.
Accessibility? What's that?
Accessible software has support for users with vision, hearing, movement/dexterity, or other impairments. It also helps users that want to use the keyboard to navigate. Out of the box web applications have some accessibility due to the nature of HTML, but this is only the case if you are using native elements in intended ways. If you cannot use native DOM elements, like <button>
, and instead must use a <div>
for buttons, then you need worry about accessibility in your page.
Supporting users with hearing impairment is not something that we can do directly for the users of Video.js. Instead we must indirectly support these users by adding support for captions in videos. In Video.js we have had support for captions and subtitles for some time, internally they are called TextTracks
. In fact Video.js has had support for WebVTT
format TextTrack
, which is much more accessible, since version 4.
Supporting users with vision impairment is harder, but partly in our control. To support this group of users our player must be accessible to screen readers. A screen reader is an application that reads elements off of the screen to the user (as the name implies). On top of reading from the screen it also allows the user to interact with the page using only the keyboard or specific gestures on a touchscreen (without using a mouse or needing to directly touch visible items). HTML has certain rules that must be followed so that a page can be accessible. We will go over the basics of these rules in the next section. Screen readers are further supported by having description tracks that can be read out during video playback. Description tracks are a sub-type of TextTrack
, and as previously stated we cannot automatically add them to videos, we can only have support for them in the Video.js.
See the resources section at the end of this post for a list of screen readers.
How do you make a web application screen reader accessible?
If you use the native elements for the purposes that they were intended, you will already have most of the work done.This is why the use of the native element is the recommended way to make anything accessible for a screen reader. For instance if you use a <button>
element you will get the following accessibility attributes (without them actually being on the button):
tabIndex
which allows users to tab to the buttonrole="button"
which tells the screen reader that this is a button- The space and the enter key will both press the button
In some cases, such as in Video.js, it will not be possible to use the native <button>
element. You will have to mimic the accessible functionality from the list above and use a div
. Here is a list of what you will have to add:
- You have to add the
role="button"
attribute to classify it as a button. - You have to add a
tabIndex
which will allow thediv
to be navigated to using thetab
key - You have to add handling for the space and enter key that press the button
A list of
role
attribute values can be found on Mozilla Developer Network.
After mimicking or adding native accessibility on the controls and content in your webpage, the next thing to look over are aria
attributes. For instance, we use aria-live="polite"
for our ProgressBar
slider. By default aria-live
is set off
, which means updates to controls should not be read to the user unless they un-focus and re-focus an element. The value of polite
which we use allows us to convey the position of the slider to screen reader without them having to change focus on the control. This is useful because the ProgressBar
is always updating while a video is playing. A value of polite
will also wait to convey said updates until the screen reader is done reading other information to the user.
For a more complete list of ARIA attributes see the specification.
Finally you need to add an accessible "name" to an element so that it can be referred to. A good example of this is can be seen in the MuteToggle
control. Since it is not a simple "button" we include innerHTML
/innerText
of "Mute" or "Unmute" in a way that is hidden from most users but announced to screen readers. In Video.js we refer to the accessible name and the action that a control performs as "control text". Control text also updates the title
attribute of an element in most cases, which is important for visual accessibility. When the action the a control performs changes so does the control text. This will allow the screen reader to refer to the MuteToggle
as "Mute Toggle" rather than "button". It will also convey the current action of the MuteToggle
. In this case that will be either "Mute" or "Unmute" depending on what the button would do when pressed (ie the state of the button).
Here are some examples of accessibility straight from Video.js:
- The
MuteToggle
<button>
:- Has
aria-live
set topolite
, rather than the default value ofoff
.aria-live
with any value other thanoff
indicates thatinnerText
/innerHTML
updates can be sent to the screen reader without the user needing to move focus off of the control. The value ofpolite
means that the screen reader should wait until it is done speaking to convey these updates to the user. - Has control text of "Mute" or "Unmute" which indicates the current status of the button to the use
- Has
- The
VolumeBar
slider<div>
:- Has a
role
attribute with a value ofslider
. Like this:role="slider"
- Has a
tabIndex
attribute as it is not a native control element - Has
EventHandlers
that listen for:- The up and right arrow keys to increase the volume and the slider percentage
- The down and left arrow keys to decrease the volume and the slider percentage
- Has
aria-label
of "volume level" which is an accessible label that the screen reader will use to refer to it - Has
aria-valuenow
andaria-valuetext
properties that update to indicate the current volume level (so the screen reader can read it) - Has
aria-live
set topolite
, rather than the default value ofoff
.aria-live
with any value other thanoff
indicates thatinnerText
/innerHTML
updates can be sent to the screen reader without the user needing to move focus off of the control. The value ofpolite
means that the screen reader should wait until it is done speaking to convey these updates to the user.
- Has a
The problem and the solution
Now let's talk about how screen reader accessibility broke in Video.js 5. First VolumeMenuButton
replaced MuteToggle
and VolumeControl
on the ControlBar
. VolumeMenuButton
was set to mimic MuteToggle
when clicked. It would also show the VolumeControl
on mouseover or focus. This was a problem because a VolumeControl
was a now a child of a button, and buttons should not contain other controls. To the screen reader and to the DOM there are two MuteToggle button
controls. When visually there is a VolumeControl
and a MuteToggle
. Below you can see a gif of this behavior in action :
The solution to this problem was to use a regular div
to house the MuteToggle
and VolumeControl
. This regular div
would have no role or control text so that it would be invisible to a screen reader. From that point forward we just needed to mimic the old UI. For those who are wondering, this new Component
is called the VolumePanel
. See the new behavior in a gif below:
Outlines
Another big accessibility fix for controls comes from the removal of one small css rule:
outline: none;
Why did we do it? With feedback from the community and external resources, we learned that outlines should always be on. Without outlines there is no visual indication of keyboard focus on control elements and without that, keyboard users who are not visually impaired have a hard time using the controls.
Wrap up
Hopefully this post has given you some insight into making a web application accessible. If you find any issues or have any suggestions for our accessibility or in general feel free to contribute to Video.js.
If you want to keep up to date on the current state of accessibility work see the a11y label on PRs and issues.
Resources
Here are some popular screen readers that are actually used in the wild:
Resources for learning more about web accessibility: