ARIA Example -- Carousel

Notes

The carousel is completely accessible.

Step by Step: How we made the carousel accessible

In the discussion on ARIA, we discussed 5 steps to making complex things accessible with ARIA.
Lets take a quick look at them again.

Step 1: Set roles.

Our buttons are HTML standard form controls so we do not need form control roles as well. The carousel items are list items, which is accurate. However the carousel container is a live region, so although we do not set its role we will set aria-live property when we get there.

Step 2: Set properties and important relationships

We want to make sure the structure, relationships between elements and groups, properties and labels are all clear in the code. They can be clear from the standard HTML code, or using ARIA.

Firstly note the structure.

So the the groups are clear.

Now lets look at the relationships between groups.

What about properties?

The content of the carousel changes so we will use aria-live="polite". This means that the user will be read the new content at the next convenient point. However the user will not be interrupted in the middle of a task.

Quick reminder....

and labels?

Looking at the buttons' fieldset - it is clear visually that they are buttons for the carousel, but they do not have a legend. So I used aria-label="carousel buttons" to give them a label for screen readers.

The buttons for next, previous and pause used symbols that made sense visually but do not make sense when read - so they also needed a labels.

Altogether the code for the buttons looked like this:

<fieldset aria-label="carousel buttons" class="carousel-buttons" aria-controls="carousel">
<button value="pause" id="pause" aria-label="pause" class="carousel-button">||</button> <button value="go" id="go" class="carousel-button">play</button>
<button value="prev" aria-label="previous" id="prev" class="carousel-button"><<</button>
<button value="next" id="next" aria-label="next" class="carousel-button">>></button>
</fieldset>

Step 3: Set the initial states

A good rule of thumb is elements that change how they look often have states that can change.

The carousel items change how they look. They go from being visible to invisible. So we are going to use aria-hidden="false" on the carousel items that is shown and aria-hidden="true" on the carousel items that are hidden.

For example

<li aria-hidden="true" class="carousel-item" id="item-3" >
<img src="three.jpg" alt="3" class="carousel-image" />
<h2 class="carousel-heading">Item 3 <span class="block">for your carousel</span></h2>
<div><p>Your carousel can show pictures and text that help you brand your website ad company.</p></div>
</li>

Note that this item has a header and an image in it. As per accessibility best practice the heading is marked as a heading and the image has good alt text.

We also use CSS selectors, to show and hide the carousel items based on the aria-hidden value. Now I do not need to change their CSS class in the code, only the value of aria-hidden.

li[aria-hidden='true'] { display: none; }
li[aria-hidden='false'] { display:block ; }

A word about backward compatibility....

Unfortunately IE 9 does not support the CSS selectors above. (IE 10 does support them.) So to make this work with older browser I added a class hidden:

.hidden {display:none;}

I then added "hidden" to the class attribute in the HTML to hide the hidden items in older browsers.

class = "... hidden"


Step 4: Set changes in state.

We discussed above that the carousel items use the aria state of aria-hidden, and we are using CSS selectors so that when ever aria-hidden='true' the item will be hidden and when aria-hidden='false' the item will be visible.

In the code we have a function to switch slides - IE it will hide the old carousel item and show the new carousel item (variable slide) by changing the values of aria-hidden.

$("li.carousel-item").attr("aria-hidden","true");
....
$("li.carousel-item:eq("+slide+")").attr("aria-hidden","false");

For backward compatibility, whenever I set aria-hidden = "true" in the script, I also added the class hidden to the same selector:

$("....").addClass("hidden");

I also removed it when I set aria-hidden = "false":

$("...").removeClass("hidden");

This makes the script much more robust in older browsers.

Step 4: Manage focus and keyboard accessibility.

This is relatively easy in this example. There are no widgets that need the focus managed as standard HTML controls have been used for all the buttons, and any content that is hidden is removed from the DOM.

However we do need to make sure our jQuery selectors are device independent. In the code we have used mouse events such as "click()" to trigger the button function such as : "$("button#next").click(function()". We need to add device independent events as well for people who can not use a mouse.

We use a single function so that the keypress event will trigger the click event on all the buttons. Here it is:

$("button").keypress(function(ev) {
if (ev.which ==13) {
$(this).click();
ev.preventDefault();
}
});

That will work on all button elements. If you have other tags that are clickable using jQuery you will need to add their selector to the function.

Note the use of preventDefault() after setting the  focus. This will prevent an extra shift-tab from occurring. PreventDefault() ensures that the default action is not executed. You can use a jQuery return false, but that will also ensures that a stopPropagation() is executed - prohibiting parent elements from receiving these events as well.

Accessibility 2.0

Managed by Lisa Seeman