EPUB 3 Accessibility Guidelines

WAI-ARIA & Custom Controls

Similar to the way that the epub:type attribute adds semantics to elements, the WAI-ARIA role attribute can be used to inform assistive technologies about the function a custom control serves (e.g., to indicate that an image functions like a button). The list of supported roles for custom controls follows:


Defining the type of a control using the role attribute is only the first step. The state of the control, and any properties associated with it, must also be maintained to ensure the reader can correctly interact with the control:

ARIA defines the following states and properties:


Example

Example 1 — Indicating an image represents a button using a role
<img src="controls/start.png"
     id="audio-start"
     role="button"
     tabindex="0"
     alt="Start"/>
Example 2 — Maintaining state using JavaScript

The following simple example shows some of the considerations that have to be paid attention to when creating a custom control: setting and unsetting callback functions, enabling and disabling the control, changing the visual appearance of the buttons. To make this image work with keyboards, the reader's keypresses must also be monitored and actions turned on and off.

<img src="controls/play.png"
     id="audio-start"
     alt="Start"
     role="button"
     aria-disabled="false"
     tabindex="0"
     onclick="controlPlayback('start')"/>

<img src="controls/stop.png"
     id="audio-stop"
     alt="Stop"
     role="button"
     aria-disabled="true"
     tabindex="0"/>

<script type="text/javascript">
<![CDATA[
function controlPlayback(action) {

  var isStart = (action == 'start') ? true : false;
  
  var start_image = isStart ? 
              'controls/play-disabled.png' : 
              'controls/play.png';
  
  var stop_image = isStart ? 
              'controls/stop.png' : 
              'controls/stop-disabled.png';
  
  var start = document.getElementById('audio-start');
     start.setAttribute('aria-disabled', 
                  !start.getAttribute('aria-disabled'));
     start.setAttribute('disabled', 
                  !start.getAttribute('disabled'));
     start.onclick = isStart ? 
                null : 
                function () { controlPlayback('start'); };
     start.setAttribute('src', start_image);
  
  var stop = document.getElementById('audio-stop');
     stop.setAttribute('aria-disabled', 
                  !stop.getAttribute('aria-disabled'));
     stop.setAttribute('disabled', 
                  !stop.getAttribute('disabled'));
     stop.onclick = isStart ? 
                function () { controlPlayback('stop'); } : 
                null;
     stop.setAttribute('src', stop_image);
   
   if (isStart) {
     start.removeAttribute('onkeypress');
     stop.setAttribute('onkeypress', "if (event.keyCode==32||event.keyCode==13) { controlPlayback('stop'); }");
   }
   
   else {
     stop.removeAttribute('onkeypress');
     start.setAttribute('onkeypress', "if (event.keyCode==32||event.keyCode==13) { controlPlayback('start'); }");
   }
  
  alert(isStart ? 'Playback started!' : 'Playback stopped!');
}
]]>
</script>

The following buttons show this code in action:

Start Stop

Samples

Compliance References and Standards

Additional Resources