Creates a viewport around a list of items, where n items are visible at any time. We say that each viewport of items constitutes a slide.
Two pagination buttons ('Previous' & 'Next') will move to the previous slide or next slide respectively. Extra controls may allow access to specific slides.
There are two variants of carousel:
- A carousel with one item in the viewport is a Slideshow Carousel (pictured above).
- A carousel with more than one item in the viewport is a Filmstrip Carousel (pictured below).
You can take a look at the carousel pattern in action on our examples site.
You can get an idea of the required markup structure by viewing our bones site.
- Visible content area of the carousel. Displays a single slide.
- Contains one or more items.
- A discrete unit of content inside of a slide (e.g. a tile or image)
- A partially visible preview of an item on the next or previous slide. Peeks serves as a visual indicator that more slides exist. A non-visual equivalent would be the active (or non-"aria-disabled") state of the previous or next buttons.
- Next Button
- Moves to next slide
- Previous Button
- Moves to previous slide
- Pagination Buttons
- Move to specific slide. Also serve as visual indicators for total number of slides and current slide index
- Pagination Bar
- A scrollbar alternative to pagination buttons. Gives fuzzy visual indicator for total number of slides and current slide index
Carousel must have a heading. For example, "Trending Deals", "Watchlist".
Carousel heading should be postfixed with" - Carousel"; this text can be hidden offscreen.
Items must be marked up as a list.
Previous and next buttons must use button tags.
Pagination indicators must use button tags.
Viewport content must conform to accessibility guidelines.
Peeks must not be focusable or interactive.
If the slides can automatically progress, then the carousel must include a pause/play button.
- Slideshow Carousels should not start automatically
- Filmstrip Carousels must not start automatically
- Pause/Play button should be the first interactive element in the carousel
- Pause/Play button must always be visible
- Automatic progression must pause when keyboard focus enters widget
- Automatic progression must pause when mouse hovers over widget
This section provides interaction design for keyboard, screen reader and pointing devices.
If "previous" button has focus,
TAB key must move focus to first focusable element in view port.
If "next" button has focus,
SHIFT+TAB key must move keyboard focus to last focusable element in view port.
Items offscreen, outside of view port, must not be keyboard focusable. Keyboard user must use 'Previous' and 'Next' buttons to control the viewport.
When on first slide, the 'Previous' button should remain in tab-order but must be visually disabled.
When on last slide, the 'Next' button should remain in tab-order but must be visually disabled.
Keyboard focus order summary
- Pause/Play button, if the carousel can auto-progress
- Previous button
- Controls (links, buttons, etc) belonging to items visible in the viewport
- Next button
- Pagination buttons or pagination bar, if they exist
Focus management summary
- Activate previous or next button: focus must stay on Previous or Next button.
- Activate Pause/Play button: focus must stay on the Pause/Play button.
"Next" button must be announced as “Next slide - Carousel Heading”, or words to those effect.
"Previous" button must be announced as “Previous slide - Carousel Heading”, or words to those effect.
Items outside of the viewport must not be reachable with the virtual cursor.
When on first slide, screen reader must announce "Previous" button as disabled.
When on last slide, screen reader must announce "Next" button as disabled.
When moving virtual cursor from item to item, screen reader might announce list index position.
If pagination buttons are used, slide index and count must be announced when slide changes. Example: "Trending Deals - slide 4 of 6".
If slide is updated automatically (i.e. autoplay) the update must be announced. Example: “Slide 4 of 6 - Trending Deals”, or “Slide updated - Trending Deals” if no pagination buttons present.
Play button label must be “Play - Trending Deals”, or words to that effect.
Pause button label must be “Pause - Trending Deals”, or words to that effect.
Clicking "Next" must update viewport with next slide.
Clicking "Previous" must update viewport with previous slide.
Clicking pagination button or pagination bar must update viewport with respective slide.
Our sample implementation follows the Progressive Enhancement strategy; we build in a layered fashion that allows everyone to access the content of the carousel.
The three layers are:
- Content (HTML)
- Presentation (CSS)
- Behaviour (JS)
The goal of our content layer is to add the list of items.
As usual we begin with our root element:
<div class="carousel"> <!-- content will go here --> </div>
We are going to create a list of vintage video games for sale on eBay, so we add a heading of "Video Games".
The heading is also post-fixed with the clipped text, "Carousel". This additional contextual text lets non-sighted users know they are dealing with a carousel pattern.
<div class="carousel"> <h2 class="carousel__title">Video Games<span class="clipped"> - Carousel</span></h2> <!-- content will go here --> </div>
The buttons must be inserted before and after the items, acting as bookends for the items.
<div class="carousel"> <h2 class="carousel__title">Video Games<span class="clipped"> - Carousel</span></h2> <button aria-label="Previous slide - Video Games" class="carousel__previous" disabled type="button"></button> <!-- items will go here --> <button aria-label="Next slide - Video Games" class="carousel__next" disabled type="button"></button> </div>
Both buttons have a property of
A carousel can contain a list of anything, for example - tiles, images, videos, static text. For our example it will be a list of video games.
Each item will contain an image, heading, format, price + shipping.
<div class="carousel"> <h2 class="carousel__title">Video Games<span class="clipped"> - Carousel</span></h2> <button aria-disabled="true" aria-label="Previous slide - Video Games" class="carousel__previous" type="button"></button> <ul> <li> <img src="horace.jpg" alt="" /><h4> <a href="http://www.ebay.com/sch/i.html?_nkw=Horace+%26+the+Spiders">Horace & the Spiders</a></h4> <p>Spectrum 48K</p> <p>$4.99 - Free Shipping</p> </li> <li> <img src="dragon.jpg" alt="" /><h4> <h4><a href="http://www.ebay.com/sch/i.html?_nkw=Double+Dragon">Double Dragon</a></h4> <p>Spectrum 48K</p> <p>$4.99 - Free Shipping</p> </li> <li> <img src="dizzy.jpg" alt="" /><h4> <h4><a href="http://www.ebay.com/sch/i.html?_nkw=Treasure+Island+Dizzy">Treasure Island Dizzy</a></h4> <p>Spectrum 48K</p> <p>$4.99 - Free Shipping</p> </li> ... </ul> <button aria-label="Next slide - Video Games" class="carousel__next" type="button"></button> </div>
Again, if you consider this content non-important, you may wish to not use progressive enhancement and render the carousel in it's entirety on the client. I will also add, rather wryly, if the content is not important, then why render it at all.
This section is coming soon.
The visual goal of the behaviour layer is to replace the primitive horizontal scrollbar with custom slide transitions. These transitions are triggered with the "Previous", "Next" and pagination buttons (if they exist). On touch-screen devices these transitions are also triggered with swipe gestures.
The semantic goal is to ensure that no device is able to access items in any other slide than the current, active slide.
Implementing CSS transitions and swipe gestures are outside the scope of this guide. Instead, our main focus will be ensuring the robust, accessible state of the carousel.
We assume the first slide will be the active slide, therefore the "Previous" button will be partially disabled.
What do we mean by partially disabled?
We say "partially" disabled when we want an inoperable button to remain keyboard focusable. The inoperable button must be aurally and visually disabled using ARIA (i.e. aria-disabled) and CSS (e.g. opacity) respectively.
Why leave the button keyboard focusable?
First of all, the button acts as a bookend, giving a strong clue to non-sighted users that they are dealing with a carousel when tabbing through page. If the button was not focusable, the user would tab straight into the first list item.
Secondly, these buttons may frequently flip back and forth between operable and inoperable; even while focus is on a button. If the button changes state to inoperable while focus is on the button, we want focus to remain in place rather than move somewhere unexpected.
<div class="carousel"> <h2 class="carousel__title">Video Games<span class="clipped"> - Carousel</span></h2> <button aria-disabled="true" aria-label="Previous slide - Video Games" class="carousel__previous" type="button"></button> <!-- items will go here --> <button aria-label="Next slide - Video Games" class="carousel__next" type="button"></button> </div>
This remainder of this section is coming soon.
This section gives an overview of ARIA usage within the context of the carousel pattern.
Used to notify user that "Next" or "Previous" buttons are in a disabled state. Screen readers will announce 'disabled,' 'dimmed,' 'unavailable,' or words to that effect.
Used to create a live status region for updates to carousel viewport, e.g "Trending Deals - slide 4 of 6”.