Carousel
UI pattern
A carousel presents a set of content items, called slides, one or more at a time. Users move between slides with its controls, and some carousels also rotate through them automatically. A slide can hold any content, though an image is common.
A carousel has a container that holds all of its parts, including the slides and the previous and next slide controls. A carousel that rotates automatically also has an automatic-rotation control to stop and restart the movement. Some add a slide picker, often styled as a row of small dots, for jumping straight to a slide.
You can add a slide picker to a carousel in one of two ways:
- A set of slide buttons, one for each slide, can be added to a conventional carousel without changing its structure. In this pattern, each slide button is a tab stop.
- A tablist with a tab for each slide can be added to a carousel with a few ARIA modifications to form a tabbed carousel. In this pattern, the picker is a single tab stop.
Tabs and accordions also let users control what's presented on a page, and they are included in Related Patterns. Unlike a tablist, a carousel has previous and next controls and may rotate automatically.
When to Use
Use a carousel when:
- You have several related items of similar weight, such as featured articles or photos, and showing only some of them at a time in a limited space is an acceptable trade-off.
- Users can reach the same items elsewhere on the site, or missing some of them costs little.
Don't use a carousel when:
- Every user needs the content. Show it.
- Users only pick between views of a topic, with no previous and next controls and no automatic rotation. Build a tablist.
- A static list or grid would fit the space. It presents the same items without making users wait for them or operate controls to find them.
Examples
Code in this section is meant to demonstrate techniques rather than requirements and lacks features needed in a production application.
The first example is a conventional carousel with an automatic-rotation control and previous and next buttons, and no slide buttons. The second is a tabbed carousel that doesn't rotate automatically, which users move through with its previous and next buttons and its picker.
Conventional Carousel With Automatic Rotation
This carousel's container is a <section> element named by its heading, which makes it a region, and aria-roledescription tells users it's a carousel. Its controls come before the slides in the DOM, with the automatic-rotation control first. Each slide is a group named by its own heading, and the slides that aren't on screen carry the hidden attribute. The element wrapping the slides is a live region.
Conventional carousel HTML
<section
class="carousel"
aria-roledescription="carousel"
aria-labelledby="carousel-heading">
<h2 id="carousel-heading">
Featured Recipes
</h2>
<div class="carousel-controls">
<button
type="button"
class="rotation">
Start slide rotation
</button>
<button
type="button"
class="previous"
aria-controls="carousel-slides"
aria-label="Previous slide">
‹
</button>
<button
type="button"
class="next"
aria-controls="carousel-slides"
aria-label="Next slide">
›
</button>
</div>
<div
id="carousel-slides"
aria-live="polite"
aria-atomic="false">
<div
role="group"
aria-roledescription="slide"
aria-labelledby="slide-1-heading">
<h3 id="slide-1-heading">
Lemon Tart
</h3>
<!-- slide content -->
</div>
<div
role="group"
aria-roledescription="slide"
aria-labelledby="slide-2-heading"
hidden>
<h3 id="slide-2-heading">
Mushroom Risotto
</h3>
<!-- slide content -->
</div>
<!-- more slides -->
</div>
</section>This carousel's script starts automatic rotation on page load unless users have asked their system to reduce motion. The script stops rotation when keyboard focus moves into the carousel anywhere but the automatic-rotation control, and pauses it while a pointer is over the carousel. The live region is off while the carousel rotates automatically and polite while it doesn't, and the previous and next buttons wrap at the ends.
Conventional carousel JavaScript
class Carousel {
#slides
#region
#rotation
#current = 0
#timer = null
#rotating = false
#hovered = false
constructor(root) {
this.#rotation = root.querySelector('.rotation')
const next = root.querySelector('.next')
this.#region = document.getElementById(
next.getAttribute('aria-controls')
)
this.#slides = [...this.#region.children]
this.#rotation.addEventListener('click', () => {
this.#rotating ? this.stop() : this.start()
})
root.querySelector('.previous').addEventListener('click', () => {
this.show(this.#current - 1)
})
next.addEventListener('click', () => {
this.show(this.#current + 1)
})
// focus inside the carousel stops rotation
root.addEventListener('focusin', (event) => {
if (event.target !== this.#rotation) this.stop()
})
// a pointer over the carousel pauses rotation
root.addEventListener('pointerenter', () => {
this.#hovered = true
})
root.addEventListener('pointerleave', () => {
this.#hovered = false
})
}
show(index) {
const count = this.#slides.length
// wrap from the last slide to the first, and back
this.#current = (index + count) % count
this.#slides.forEach((slide, i) => {
slide.hidden = i !== this.#current
})
}
start() {
this.#rotating = true
this.#region.setAttribute('aria-live', 'off')
this.#rotation.textContent = 'Stop slide rotation'
this.#timer = setInterval(() => {
if (!this.#hovered) this.show(this.#current + 1)
}, 5000)
}
stop() {
this.#rotating = false
clearInterval(this.#timer)
this.#region.setAttribute('aria-live', 'polite')
this.#rotation.textContent = 'Start slide rotation'
}
}
document.addEventListener('DOMContentLoaded', () => {
const reduceMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches
document.querySelectorAll('.carousel').forEach((root) => {
const carousel = new Carousel(root)
if (!reduceMotion) carousel.start()
})
})Tabbed Carousel With Manual Rotation
This carousel's container is the same as in the first example. It has no automatic-rotation control, so its live region stays polite. Its picker is a tablist named "Slides", after the previous and next buttons and before the slides.
Each slide is a tab panel with aria-roledescription="slide", and each tab and its slide share a name through aria-labelledby, which points both at the slide's heading. The element wrapping the slides has tabindex="0", so it's a tab stop when a slide doesn't start with a focusable element.
When users press previous or next, the script shows the new slide and moves aria-selected="true" and tabindex="0" to its tab.
The picker is a single tab stop: only the selected tab has tabindex="0". The Left Arrow and Right Arrow keys move focus between the tabs, wrapping at the ends, and Home and End move to the first and last tabs. Each tab shows its slide as soon as it takes focus.
Tabbed carousel HTML
<section
class="carousel"
aria-roledescription="carousel"
aria-labelledby="carousel-heading">
<h2 id="carousel-heading">
Featured Recipes
</h2>
<div class="carousel-controls">
<button
type="button"
class="previous"
aria-controls="carousel-slides"
aria-label="Previous slide">
‹
</button>
<button
type="button"
class="next"
aria-controls="carousel-slides"
aria-label="Next slide">
›
</button>
</div>
<div class="carousel-tabs" role="tablist" aria-label="Slides">
<button
id="carousel-tab-1"
type="button"
role="tab"
tabindex="0"
aria-labelledby="slide-1-heading"
aria-selected="true"
aria-controls="slide-1">
●
</button>
<button
id="carousel-tab-2"
type="button"
role="tab"
tabindex="-1"
aria-labelledby="slide-2-heading"
aria-selected="false"
aria-controls="slide-2">
○
</button>
<!-- more tabs -->
</div>
<div
id="carousel-slides"
tabindex="0"
aria-live="polite"
aria-atomic="false">
<div
id="slide-1"
role="tabpanel"
aria-roledescription="slide"
aria-labelledby="slide-1-heading">
<h3 id="slide-1-heading">
Lemon Tart
</h3>
<!-- slide content -->
</div>
<div
id="slide-2"
role="tabpanel"
aria-roledescription="slide"
aria-labelledby="slide-2-heading"
hidden>
<h3 id="slide-2-heading">
Mushroom Risotto
</h3>
<!-- slide content -->
</div>
<!-- more slides -->
</div>
</section>Tabbed carousel JavaScript
class TabbedCarousel {
#tabs
#slides
#current = 0
constructor(root) {
this.#tabs = [...root.querySelectorAll('[role="tab"]')]
this.#slides = this.#tabs.map((tab) =>
document.getElementById(tab.getAttribute('aria-controls'))
)
root.querySelector('.previous').addEventListener('click', () => {
this.select(this.#current - 1)
})
root.querySelector('.next').addEventListener('click', () => {
this.select(this.#current + 1)
})
this.#tabs.forEach((tab, i) => {
tab.addEventListener('click', () => this.select(i))
tab.addEventListener('keydown', (event) => this.#onKey(event))
})
}
select(index, focus = false) {
const count = this.#tabs.length
// wrap from the last slide to the first, and back
this.#current = (index + count) % count
this.#tabs.forEach((tab, i) => {
const selected = i === this.#current
tab.setAttribute('aria-selected', String(selected))
tab.tabIndex = selected ? 0 : -1
this.#slides[i].hidden = !selected
})
if (focus) this.#tabs[this.#current].focus()
}
#onKey(event) {
const i = this.#tabs.indexOf(event.currentTarget)
const moves = {
ArrowRight: i + 1,
ArrowLeft: i - 1,
Home: 0,
End: this.#tabs.length - 1,
}
if (!(event.key in moves)) return
// keep the page from scrolling on the same key press
event.preventDefault()
this.select(moves[event.key], true)
}
}
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.carousel').forEach((root) => {
new TabbedCarousel(root)
})
})Structure and Semantics
A carousel tells users four things: that it's a carousel, which one it is, which slides are on screen, and how to move between them. The container's role description carries the first and its name the second. The slides' names and the live region carry the third, and the controls carry the fourth.
No HTML element conveys a carousel, so the container and the slides carry ARIA. The controls are buttons, native or custom.
Both patterns share most of their structure. A container holds every part of the carousel. Inside it, the controls come first: previous and next buttons and, in a carousel that rotates automatically, an automatic-rotation control that stops and restarts the movement. After the controls, an element wraps the slides and reports the slide changes users make.
The patterns differ in their slides and their slide picker. In a conventional carousel, the slides are groups, and slide buttons, when there are any, sit among the other controls. In a tabbed carousel, the picker is a tablist and the slides are tab panels that share a name with their tabs.
Carousel Container
A <section> element with an accessible name, or role="region", makes the container a landmark region, which suits a carousel important enough to list among the page's landmarks:
| Attribute | How to use |
|---|---|
role | Set to "region", or use a named <section>, for a carousel that belongs among the page's landmarks, and set to "group" otherwise. |
aria-roledescription | Set to "carousel". |
aria-labelledby or aria-label | Name the container from its visible heading, or with aria-label when there isn't one. Leave the word "carousel" out of the name. |
Slides Wrapper
The element wrapping the slides is a live region:
| Attribute | How to use |
|---|---|
aria-live | Set to "off" while the carousel rotates automatically, and to "polite" while it doesn't. |
aria-atomic | Set to "false", so only the slide that changed is reported. |
Slides
In a conventional carousel, each slide is a group:
| Attribute | How to use |
|---|---|
role | Set to "group" on each slide. |
aria-roledescription | Set to "slide" on each slide. |
aria-labelledby or aria-label | Give each slide a name that identifies it and sets it apart from the others, such as from its heading or an image's alternative text. Adding its position, such as "3 of 6", tells users where it sits in the set. Leave the word "slide" out of the name. |
In a tabbed carousel, each slide is a tab panel:
| Attribute | How to use |
|---|---|
role | Set to "tabpanel" on each slide. |
aria-roledescription | Set to "slide" on each slide, as in a conventional carousel. |
aria-labelledby | Set to the id of the slide's tab, or of the slide's heading when the tab's aria-labelledby also points at it, so the tab and slide share a name. |
Slide Controls
The previous and next buttons and the automatic-rotation control carry the button role, natively or through ARIA:
| Attribute | How to use |
|---|---|
aria-label | Names a control that shows only an icon. Visually hidden text inside the button, or an SVG <title> that aria-labelledby references, works as well. |
aria-controls | Set on the previous and next buttons to the id of the element wrapping the slides. |
aria-pressed | Only on an automatic-rotation control built as a toggle button with a fixed name, such as "Automatic rotation": "true" while the carousel rotates automatically and "false" while it doesn't. A control whose name changes between stop and start, as in the conventional example, carries none. |
disabled or aria-disabled | Disable a previous or next button that can't go further with one of the two, never both. disabled takes the button out of the tab order, and aria-disabled="true" keeps it there. |
Slide buttons, in a carousel that has them, carry the button role too, one for each slide:
| Attribute | How to use |
|---|---|
aria-label or aria-labelledby | Name each slide button so users can tell which slide it shows. The slide's own name is the simplest choice. |
disabled or aria-disabled | Disable the button for the slide on screen with one of the two, never both, as for the previous and next buttons. |
A tabbed carousel's picker is a tablist, with one tab for each slide:
| Attribute | How to use |
|---|---|
role | Set to "tablist" on the element that contains the tabs, and to "tab" on each tab. |
aria-labelledby or aria-label | Name the tablist so it identifies its content as slides, such as "Slides". |
aria-selected | Set to "true" on the tab for the slide on screen and "false" on every other tab. |
tabindex | Set to "0" on the selected tab and "-1" on the others, so the picker is a single tab stop. |
aria-controls | Set on each tab to the id of the slide it shows. |
aria-disabled | Set to "true" on a tab that can't be selected. |
Icons have a contrast ratio of at least 3:1 with what's behind them (1.4.11 Non-text Contrast - AA). Slide content varies, so place the controls outside the slide area, or give each control a background of its own.
The DOM order puts the controls before the slides, and an automatic-rotation control, when there is one, should come first. When the design shows the controls elsewhere, such as arrows over the slide or dots below it, position them with CSS.
Carousel Has Controls
Users move between a carousel's slides with controls they can reach and operate: previous and next buttons, a slide picker, or both. A carousel that rotates automatically also has an automatic-rotation control. A swipe gesture or a timer on its own isn't a control.
Provides controls for browsing
Reported as: Carousel has no controls
A carousel should have controls that assistive technology reports for moving between slides, either previous and next buttons or a slide picker.
When the carousel only rotates on a timer, or its arrows are <div> elements with click handlers, keyboard and screen reader users can't choose a slide. They get whichever one is showing, or wait for the one they want.
Build the controls as buttons, from <button> elements or elements with the button role, and name each for what it does, such as "Next slide". Keep any swipe gesture as an addition to them.
Severity: Serious
Carousel Has Slides
Each slide is a container holding all of that slide's content, with aria-roledescription="slide". In a conventional carousel, it also carries role="group", and in a tabbed carousel, role="tabpanel". Screen reader users then know where each slide starts and ends, and that it's one of a set.
Describes each slide as a slide
Reported as: Slides role is not defined
Each slide in a carousel, conventional or tabbed, should carry aria-roledescription="slide".
When slides carry only their role, screen reader users hear "group" or "tab panel" at every slide, with nothing to say it's one slide of the carousel. The description on the container doesn't reach the slides inside it.
Add aria-roledescription="slide" to each element carrying a slide's group or tabpanel role, with the same value on every slide.
Severity: Minor
Makes each slide a group
Reported as: Slide not defined as group
In a conventional carousel, each slide should carry role="group".
When slides are plain <div> elements, the carousel's content reads as one continuous run, with nothing marking where a slide begins or ends, and a slide's name and aria-roledescription have no role to attach to.
Add role="group" to the element wrapping each slide's content, along with its name and aria-roledescription="slide". In a tabbed carousel, use role="tabpanel" instead.
Severity: Minor
Slide Edges
At the first and last slides, the previous and next buttons must either wrap or be disabled. When they wrap, next on the last slide shows the first, and previous on the first slide shows the last. When they don't, the button that can't go further is disabled, with disabled or aria-disabled="true".
Continues past the last item
Reported as: Carousel rotation does not loop
A carousel's previous and next buttons must either wrap at the first and last slides or report that they can't go further.
When next does nothing on the last slide and still looks and sounds available, users can't tell the end of the carousel from a broken control. When the button is removed at the end instead, focus drops out of the carousel.
Wrap from the last slide to the first and back. When the design doesn't wrap, disable the button at the end rather than removing it, using aria-disabled="true" when focus should stay on it.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Tablist Has Tabs
A tabbed carousel's picker holds one tab for each slide, and nothing else. The previous and next buttons and the automatic-rotation control sit beside the tablist, not inside it.
Leaves at least one tab operable
Reported as: No active tabs
A tabbed carousel's picker must have at least one tab that isn't disabled.
When every tab is disabled, keyboard users reach the picker and find nothing that takes focus or responds to the arrow keys, so the picker offers no way to choose a slide.
Keep a tab available for every slide users can show, and never disable the tab for the slide on screen.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Holds only tabs
Reported as: Unexpected interactive group members
Every child a picker's tablist exposes must have the tab role.
When the previous and next buttons or the automatic-rotation control sit inside the tablist beside the tabs, assistive technology can count them as part of the set, so the positions users hear no longer match the slides. The arrow keys can also stop on something that isn't a tab.
Place the carousel's other controls outside the tablist, and take decorative elements out of the accessibility tree with aria-hidden="true".
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Gives each picker tab the tab role
Reported as: No group members with required role
Each tab in a tabbed carousel's picker must carry the tab role.
When the tablist's children are buttons without role="tab", or a wrapper sits between the tablist and its tabs, assistive technology finds no tabs to report. Screen reader users are told they've reached a tab list, then hear a row of buttons with no count or selection.
Give each tab role="tab" and make it a child of the tablist. Remove any wrapper between them, or give the wrapper role="presentation".
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Role
A carousel's container carries the region or group role, and neither says what the component is, which is why it also carries aria-roledescription (see Role Description). Use a named <section> element, or role="region", when the carousel belongs among the page's landmarks, and role="group" otherwise.
The slides and the picker take the roles of one pattern. In a conventional carousel, each slide carries the group role, and slide buttons are buttons. In a tabbed carousel, the picker is a tablist of tab elements, and each slide carries the tabpanel role instead of group.
Gives the container and picker their roles
Reported as: Element has incorrect role
A carousel's container must carry the region or group role, and a tabbed carousel's picker the tablist role.
When the container is a plain <div> with no role, ARIA doesn't allow aria-roledescription or an accessible name on it, and assistive technology can ignore both. Screen reader users then get no sign that the slides and controls belong to one component. When the picker's tabs sit in a plain <div>, users aren't told how many tabs there are.
Use a <section> element with an accessible name, or add role="region" or role="group" to the container. Add role="tablist" to the element that directly contains the tabs.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Uses one pattern for the picker
Reported as: Incorrect picker role
A carousel's slide picker should follow one pattern: slide buttons, with slides that are groups, or a tablist of tab elements, with slides that are tab panels.
When the picker is a row of <div> or <span> dots with click handlers, it reaches assistive technology as nothing, and screen reader users can't find it. When it mixes the two patterns, such as buttons inside a tablist, or tabs whose slides are still groups, it belongs to neither, and users get controls that don't behave the way their roles promise.
Pick one pattern and carry it through, from the picker to the slides.
Severity: Serious
Puts each role on the part it names
Reported as: Incorrect root element
Sanity check. Evinced checks that the carousel's role sits on the container that holds its controls and slides, and the picker's tablist role on the element that directly contains the tabs. This check runs on every UI pattern, not only on carousels.
A carousel should carry each role on the element that is that part, not on a wrapper around it or on an element inside it.
When the region role and the carousel's name sit on an inner element while the controls sit outside it, screen reader users meet the controls before the carousel begins. When the tablist role sits on a wrapper around the tabs' parent, the tabs aren't its children, and users hear no tab count or position.
Put the container's role, name, and aria-roledescription on the element that holds every part of the carousel, and role="tablist" on the tabs' parent. Keep any layout wrapper free of roles.
Tab Panels Roles
In a tabbed carousel, each slide is the panel its tab shows, so it carries the tabpanel role in place of group, along with its aria-roledescription="slide".
Makes each tabbed slide a tab panel
Reported as: Missing tabpanel role
In a tabbed carousel, each slide must carry the tabpanel role.
When a slide that a tab shows is still a group or a plain <div>, assistive technology has no panel for the tab to control, and screen reader users can't tell that the content on screen belongs to the selected tab.
Set role="tabpanel" on each slide in place of group, and keep its aria-roledescription="slide".
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Role Description
A carousel's container carries aria-roledescription="carousel", so screen reader users hear "carousel" rather than "region" or "group". The description changes only how the role is presented, so the container still needs its region or group role. Carousel Has Slides covers the slides' description.
Describes its role in words
Reported as: Carousel role is not defined
A carousel's container should carry aria-roledescription="carousel".
When it doesn't, screen reader users hear "region" or "group" and the carousel's name. That tells them a section of the page begins, but not that its content changes or that it has slide controls.
Add aria-roledescription="carousel" to the element carrying the region or group role. Translate the value along with the page's content, since screen reader users hear it as written.
Severity: Moderate
Adds meaning the role lacks
Reported as: Redundant Role description
An aria-roledescription in a carousel should say something its role doesn't.
When the value repeats the role, such as "region" on the container or "button" on a control, or when it's empty, it adds nothing. On a control, it also replaces the role name users rely on to know how to operate it.
Use aria-roledescription only on the container, set to "carousel", and on the slides, set to "slide". Remove it everywhere else.
Severity: Minor
Button Name
Each carousel control is named for what it does, such as "Previous slide", "Next slide", or "Stop slide rotation", and each slide button for the slide it shows. Arrows and dots have no text to take a name from, so an icon-only control needs a name added.
Has an accessible name
Reported as: Accessible name
Each button in a carousel must have an accessible name that says what it does.
When a previous or next button shows only an arrow character or an icon, or a slide button only a dot, screen readers announce "button" or read the character out. Users can't tell the controls apart or know which slide a dot shows.
Name an icon-only control with aria-label, as the examples' previous and next buttons do, or with visually hidden text inside it. Name each slide button after its slide.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Accessibility Label
A carousel's container has an accessible name that says which carousel this is, such as "Featured recipes". The name leaves out the word "carousel", since aria-roledescription already supplies it. In a tabbed carousel, the tablist has a name too, one that identifies its content as slides, such as "Slides".
Names the carousel
Reported as: Missing contextual labeling
A carousel's container must have an accessible name.
When it has none, screen reader users entering it hear that they've reached a carousel and nothing about which one or what it holds. On a page with two carousels, the two sound the same.
Name the container from its visible heading with aria-labelledby. When there's no visible heading, use aria-label. Name a tabbed carousel's picker as well, such as "Slides".
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Leaves the role out of the name
Reported as: Redundant role in name
A carousel's accessible name should leave out the word "carousel".
When the name includes the word, screen reader users hear it twice, as in "Featured recipes carousel, carousel", and the part that identifies the carousel comes later.
Remove the word from the name and let aria-roledescription supply it. When a visible heading has to keep the word, point aria-labelledby at an element holding only the distinguishing part, or use a shorter aria-label.
Severity: Minor
Tabs Accessibility Labels
In a tabbed carousel, each tab has an accessible name that identifies the slide it shows. The simplest choice is the slide's own name, but any name works if users can tell which slide the tab shows. The tablist already reports each tab's position, as in "tab 3 of 6", so a position in the tab's name is redundant.
Names each tab
Reported as: Group members missing accessible names
Each tab in a tabbed carousel's picker must have an accessible name.
When a tab shows only a dot, screen reader users hear "tab, 2 of 5", with nothing to say which slide it shows.
Name each tab after the slide it shows, with aria-labelledby pointing at the slide's heading, or with aria-label.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Tells one tab from another
Reported as: Group contains duplicate names
No two tabs in a carousel's picker should share an accessible name.
When the tabs share a name, such as "Show slide", users moving through the picker can't tell which tab shows which slide, and have to select each one to find out.
Name each tab after the slide it shows. Since the tablist already reports each tab's position, as in "tab 3 of 6", the name doesn't need one.
Severity: Serious
Tab Panels Accessibility Labels
In a tabbed carousel, each slide is a tab panel, and it shares its name with the tab that shows it, so users who pick a tab land in a slide that sounds like the tab they picked.
Names each tabbed slide
Reported as: Tabpanel does not have an accessible name
Each slide in a tabbed carousel must have an accessible name.
When a slide has only its role, screen reader users who move into it hear an unnamed slide. Someone who just picked a tab gets no confirmation of which slide they're in.
Set the slide's aria-labelledby to the id of its tab, or of the slide's heading when the tab's aria-labelledby also points at it.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Shares its name with its tab
Reported as: Tabpanel is not labeled by its control
Each slide in a tabbed carousel should share its name with its tab through aria-labelledby, not through a copy of the tab's text.
When a slide has a hand-written aria-label, its name drifts from its tab's as soon as either changes, and users who pick a tab land in a slide that sounds like a different one.
Point the slide's aria-labelledby at its tab, or point both the slide's and the tab's aria-labelledby at the slide's heading, as the tabbed carousel under Examples does.
Severity: Moderate
Slides Accessibility Labels
Each slide has an accessible name that identifies it and sets it apart from the other slides, so users can connect the name to what's on the slide. The name can come from the slide's heading, an image's alternative text, or other text, as long as that connection is clear. It leaves out the word "slide", since aria-roledescription already supplies it.
A conventional carousel has nothing that tells screen reader users where a slide sits in the set, since the group role doesn't support aria-posinset or aria-setsize. Adding the position to each slide's name, such as "3 of 6", fills that gap.
Names each slide
Reported as: Group members missing accessible names
Each slide in a carousel must have an accessible name.
When slides have none, screen reader users moving through the carousel hear "slide" and its content, with nothing to say which slide they've reached or whether the control they pressed changed it.
Name each slide from content that identifies it, such as its heading or an image's alternative text, with aria-labelledby or aria-label. In a conventional carousel, adding the slide's position, such as "2 of 5", also tells users where it sits in the set.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Tells one slide from another
Reported as: Group contains duplicate names
No two slides in a carousel should share an accessible name.
When every slide takes its name from the same text, such as a repeated "Learn more" caption, users can't tell whether pressing next took them to another slide or left them where they were.
Name each slide from content that sets it apart, such as its heading, its title, or an image's alternative text. When the slides have no distinct text, describe what each one shows. In a conventional carousel, a position such as "3 of 6" can also tell slides apart.
Severity: Serious
Leaves the role out of slide names
Reported as: Redundant role in name
A slide's accessible name should leave out the word "slide".
When the name includes the word, screen reader users hear it twice, as in "Slide 3, slide", and the part that identifies the slide comes later.
Remove the word from the name and let aria-roledescription="slide" supply it, so "Slide 3 of 6" becomes "3 of 6".
Severity: Minor
aria-live
A carousel reports the slide changes users make and stays quiet about the ones it makes by itself. The element wrapping the slides carries aria-live. Its value is off while the carousel rotates automatically and polite while it doesn't, so screen reader users hear the new slide's content after pressing previous or next. The same element also carries aria-atomic="false", so only the slide that changed is reported.
A carousel that rotates automatically also lets users stop it, so a slide stays on screen until they move on.
Lets users stop automatic rotation
Reported as: Carousel auto-rotation can't be stopped
A carousel that rotates automatically must give users a way to stop the rotation.
When the slides keep moving, some users can't finish reading a slide before it changes, and others can't keep their attention on the rest of the page. Pausing only while a pointer is over the carousel doesn't help keyboard or screen reader users.
Add an automatic-rotation control that stops the movement and keeps the carousel stopped until users start it again, and place it first among the carousel's controls.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.2.2 Pause, Stop, Hide (A) | For moving, blinking, scrolling, or auto-updating information, a mechanism exists to pause, stop, or hide it, with specific exceptions for essential activity and time-based media. |
| EN 301 549 | 9.2.2.2 Pause, Stop, Hide | Same as the WCAG text. |
| Section 508 | 1194.21(h) | When animation is displayed, the information shall be displayable in at least one non-animated presentation mode at the option of the user. |
Announces the slide it moves to
Reported as: Carousel missing aria-live
A carousel must report a slide change that users make with its controls.
When no live region covers the slides, users press next and hear nothing. They can't tell whether the control worked without reading back through the carousel.
Set aria-live="polite" on the element wrapping the slides whenever the carousel isn't rotating automatically, and keep that element in the page from first render. Show a slide by adding it to the accessibility tree, such as by removing hidden, rather than by rewriting text that's already there.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.3 Status Messages (AA) | In content implemented using markup languages, status messages can be programmatically determined through role or properties such that they can be presented to the user by assistive technologies without receiving focus. |
| EN 301 549 | 9.4.1.3 Status Messages | Same as the WCAG text. |
Uses a single live region
Reported as: Multiple live regions
A carousel should have one live region covering its slides.
When the wrapper, the slides inside it, and a position indicator such as "2 of 5" each carry aria-live, one press of a control sets off several announcements of the same change, and they can cut each other off.
Keep aria-live on the element that wraps the slides, and remove it from the elements inside and around it.
Severity: Moderate
Stays quiet while rotating itself
Reported as: Aria-live on auto rotating carousel
A carousel that rotates automatically must turn its live region off during automatic rotation.
When the region stays polite, screen reader users hear a new slide every few seconds, whatever they're reading elsewhere on the page, and can't stop it without finding the automatic-rotation control.
Set aria-live="off" when automatic rotation starts and polite when it stops, in the same code that starts and stops the timer.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Set Size
When every tab of a tabbed carousel's picker is in the DOM, the browser works out the size of the set without aria-setsize. Set it only when the picker renders some of its tabs, and then give every tab the same value: the total number of slides.
Reports one total for the set
Reported as: Aria-setsize conflicting values
Every tab in a tabbed carousel's picker must declare the same aria-setsize.
When the total is written to each tab as slides load and never updated on the others, the count changes as users move through the tabs, from "2 of 4" to "3 of 5". Users can't tell how many slides there are.
Write the total to every tab from one source, and update it on all of them when a slide is added or removed. When the full number isn't known yet, leave the attribute off.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Carries the total on each tab
Reported as: Aria-setsize invalid implementation
A picker should set aria-setsize on each tab, not on the tablist.
When the count sits only on the tablist, it never reaches assistive technology, which reads the total from the tab that has focus. Users moving through the picker hear no total.
Set aria-setsize on every tab with the same value, along with each tab's aria-posinset, in the same code that renders the tabs.
Severity: Minor
Set Position
When every tab of a tabbed carousel's picker is in the DOM, the browser works out each tab's position without aria-posinset, and the tab and slide names need no count. Set it only when the picker renders some of its tabs, and then number each tab by its slide's place in the full set.
The group role doesn't support the attribute, so in a conventional carousel a slide's position goes in its name, such as "3 of 6".
Fits each position in the set
Reported as: Aria-posinset is larger than aria-setsize
A tab's aria-posinset must be a whole number from 1 up to its aria-setsize.
When positions come from an array index, or from the tabs currently rendered rather than every slide, screen reader users hear something that can't be true, such as "tab 5 of 4", and lose track of how many slides there are.
Derive the position and the size from the same list of slides, start positions at 1, and recompute both when slides are added or removed.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Carries the position on each tab
Reported as: Aria-posinset invalid implementation
A picker should set aria-posinset on each tab, not on the tablist.
When the attribute sits on the tablist, it has no effect, and the tabs that need a position have none. Users moving through the picker get no sense of which slide they're on.
Move aria-posinset onto each tab, numbered by its slide's place in the set, and set aria-setsize alongside it.
Severity: Minor
Keyboard Navigation Orientation
A carousel's picker is usually a horizontal row of dots, so the Left Arrow and Right Arrow keys move between its tabs, which is the tablist default. Set aria-orientation="vertical" only when the tabs are stacked and the Up Arrow and Down Arrow keys move between them.
Declares the orientation it uses
Reported as: Conflicting aria-orientation
A picker's aria-orientation must match the arrow keys that move focus among its tabs.
When a picker stacked beside the slides leaves aria-orientation at its horizontal default while the Up Arrow and Down Arrow keys move focus, or the reverse, screen reader users press the keys they're told to use and nothing happens.
Set aria-orientation="vertical" when the Up Arrow and Down Arrow keys move focus, and leave it off when the Left Arrow and Right Arrow keys do. Derive the attribute and the key handling from the same state.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Uses a valid aria-orientation value
Reported as: Invalid aria-orientation value
A picker's aria-orientation should be horizontal or vertical.
When the attribute holds any other value, such as row or an empty string, assistive technology ignores it and treats the picker as horizontal. Users of a vertical picker are told to use the Left Arrow and Right Arrow keys, which do nothing.
Write one of the two values, in lowercase, chosen to match the keys that move focus. For a horizontal picker, you can leave the attribute off.
Severity: Minor
aria-selected
In a tabbed carousel, the selected tab is the one for the slide on screen, and aria-selected="true" follows the slide however it changes. When the carousel rotates automatically, or users press the previous or next button, the script that shows the new slide also moves the selection to its tab.
Marks which tab is selected
Reported as: No selection attributes
Every tab in a tabbed carousel's picker must declare its selection state with aria-selected.
When the tab for the slide on screen is marked only by styling, such as a filled dot, screen reader users hear each tab's name with no indication of which slide is showing.
Set aria-selected="true" on the tab for the slide on screen and "false" on every other tab, in the same code that shows the slide, whether users pick a tab, press previous or next, or the carousel rotates automatically.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Leaves native state to HTML
Reported as: Avoid aria-checked on native elements
A picker built from native inputs, such as radio buttons for its dots, must leave their state to checked and not add aria-checked.
When each input also carries aria-checked, the two states are kept separately and can disagree as the slides change, so a dot can be reported as unchecked while its slide is the one on screen.
Remove aria-checked from the native inputs and let checked report which slide is showing.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Picks one selection state
Reported as: Mixed selection attributes
A picker's tabs should indicate selection with aria-selected only, not with aria-checked as well.
When tabs carry both attributes, the values can drift apart as the slides change, so a tab can be reported as checked and not selected at the same time. Users can't tell which state reflects the slide on screen.
Remove aria-checked from the tabs and keep aria-selected, the state assistive technology reports for a tab.
Severity: Minor
aria-pressed
An automatic-rotation control can be built two ways. A toggle button keeps a fixed name, such as "Automatic rotation", and conveys whether the carousel is rotating through aria-pressed. A command button, like the one in the conventional example, changes its name between "Stop slide rotation" and "Start slide rotation" and carries no aria-pressed. Either is valid, and these criteria apply to the toggle button.
Declares its current state
Reported as: No toggle indicator
An automatic-rotation control built as a toggle button must declare whether rotation is on with aria-pressed.
When the pressed look comes from a CSS class and aria-pressed is missing, assistive technology reports a plain button with a fixed name. Screen reader users can't tell whether the slides are moving, or whether their press stopped them.
Set aria-pressed to true while the carousel rotates automatically and false while it doesn't, starting when the control first renders. If the name has to change instead, remove aria-pressed and build a command button.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Uses a defined state value
Reported as: Invalid toggle attribute value
The aria-pressed attribute on an automatic-rotation control must be set to a value the specification defines.
When aria-pressed carries a value such as "on", "playing", or an empty string, browsers and assistive technology ignore it or assume a default of their own. Screen reader users can be told rotation is off while the slides move, or hear a plain button.
Set it to true while the carousel rotates automatically and false while it doesn't. The control governs a single state, so mixed has no meaning here.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Color Alone State Indication
An automatic-rotation control built as a toggle button keeps the same name whether rotation is on or off, so its appearance is what tells sighted users the state. That change must go beyond color.
Shows state by more than color
Reported as: State indicated by color alone
An automatic-rotation control built as a toggle button must show whether rotation is on with a visual change other than color.
When the only difference between states is the control's color, such as an icon that turns from gray to blue while the slides move, people with color vision deficiency or low vision, or using a high-contrast display, can't tell whether rotation is on. Exposing the state to assistive technology doesn't help, because most of these users don't use any.
Change the icon with the state, such as a pause symbol while the carousel rotates and a play symbol while it doesn't, and keep any color change alongside it. Whatever tells the states apart needs a contrast of at least 3:1 with the colors around it (1.4.11 Non-text Contrast - AA).
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.4.1 Use of Color (A) | Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. |
Disabled
A carousel's controls are the only parts of it that can be disabled, never the carousel itself or its slides. A control that can't be operated declares its disabled state with the disabled attribute or aria-disabled, whichever suits the element, and a control that can be operated never does.
Disables only when role allows
Reported as: Component does not support disabled state
A carousel must declare a disabled state only on its controls, not on its container or its slides.
When aria-disabled or disabled sits on the region container or on a slide, assistive technology either ignores it or reports content as unavailable even though users can still read and operate it. Users can't tell which parts of the carousel work.
Remove the attribute from the container and the slides. When a control can't act, disable that button.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Disables only elements that support it
Reported as: Element type does not support disabled state
An element in a carousel must carry disabled or aria-disabled only when its role supports a disabled state.
When the state sits on an element whose role has none, such as a wrapper, a list item or a heading, assistive technology may drop it or report it on something users can't operate, while the control that really is unavailable is still reported as available.
Remove the attribute from that element, and set the disabled state on the control itself, using an element or role that supports it, such as a native <button>.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Avoids conflicting disabled states
Reported as: Conflicting disabled values
A carousel's control must declare its disabled state one way only: the disabled attribute or aria-disabled, never both.
When a button carries both and they disagree, assistive technology can report a state the browser doesn't enforce, so screen reader users are told the wrong thing about whether previous, next, or a slide button works.
On a <button>, use disabled to take it out of the tab order, or aria-disabled="true" to keep it there while the code ignores presses. On a control built from any other element, use aria-disabled. Remove it or set it to false when the control is enabled again.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Uses aria-disabled rather than disabled
Reported as: Element does not support the disabled attribute
A carousel's control or tab built from an element other than a <button> must convey its disabled state with aria-disabled, not the disabled attribute.
When disabled is set on a <div> with role="button" or role="tab", the browser ignores it. The control stays exposed as available, so users are told they can press a button or pick a slide the design means to be unavailable, even when styling grays it out.
Set aria-disabled="true" instead, and have the code ignore presses while it's set.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Screen Readable Tab Panels
Only the slides on screen are in the accessibility tree, in conventional and tabbed carousels alike. When screen reader users can read slides nobody can see, they lose track of which slide is current, and a press of a control can change the content they're reading without warning. Hide the other slides with the hidden attribute or display: none, not by moving them off screen or making them transparent.
Puts the shown slide in the tree
Reported as: Active tab panel not available to assistive technology
The slide on screen must be exposed to assistive technology.
When the slide on screen carries aria-hidden="true", or sits inside an element that does, screen reader users reach the carousel or press next and hear none of the slide's content. In a tabbed carousel, a tab whose aria-controls points at a different slide has the same effect.
Remove aria-hidden from the slide and its ancestors in the same update that shows it. In a tabbed carousel, point each tab's aria-controls at the slide it shows.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Keeps hidden slides out of the tree
Reported as: Inactive tab panel available to assistive technology
A slide that isn't on screen must be hidden from assistive technology.
When slides are hidden with opacity: 0, zero height, or off-screen positioning, they stay in the accessibility tree. Screen reader users hear the content of every slide, one after another, with nothing to say which one is on screen.
Hide the slides that aren't on screen with the hidden attribute or display: none, and update them each time the slide changes. When slides animate from one to the next, hide the outgoing slide when the transition ends.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Visible Tab Panels
In a tabbed carousel, the slide on screen is the one whose tab is selected, including after the carousel rotates automatically. When slides animate from one to the next, hide the outgoing slide once the transition ends, so a single slide remains visible.
Displays the slide its tab selects
Reported as: Active tab panel not visible
In a tabbed carousel, the slide of the selected tab must be displayed on screen.
When a tab's aria-controls names the wrong slide, or a CSS rule keeps the slide hidden, users select a tab and see either an empty slide area or another slide. Screen reader users are told one slide is selected while sighted users see another.
Generate each tab's aria-controls and its slide's id from the same source, and show the slide from the current selection in the same update that hides the others.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Keeps other slides off screen
Reported as: Inactive tab panel visible
Only the slide of the selected tab should be displayed.
When every slide renders at once, or the outgoing slide isn't hidden as a new one is shown, content from two slides appears together. Users can't tell which content belongs to the selected tab, and people using magnification may not see where one slide ends and the next begins.
Hide every slide except the selected one, with the hidden attribute or display: none, in the same update that shows the new slide.
Severity: Serious
Forbidden Interactive Children
A carousel's buttons, and the tabs in a tabbed carousel's picker, hold only a label or an image, such as an arrow, a number, a dot, or a thumbnail. A link or button belongs in the slide itself, never inside a control.
Avoids nested interactives
Reported as: Forbidden interactive children; Nested interactive elements
A carousel's buttons, and the tabs in a tabbed carousel's picker, must not contain interactive elements, such as a link or a button.
When a slide button or tab holds a control, such as a "Read more" link copied from its slide, assistive technology may drop the inner control's role or expose only the outer one. Users hear one control where two exist, and a click or key press has two plausible targets.
Move the control into the slide, and keep only a label, a number, or an image in the button or tab.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Relationships
A carousel owns its slide picker, when it has one. In a tabbed carousel, the picker is a tablist that sits among the carousel's controls, before the slides, and each tab shows one slide. Tablist covers how to build the picker, and this entry covers how it fits into the carousel.
Each tab's aria-controls names the slide it shows, and each slide's aria-labelledby names its tab or the heading that also names its tab. The previous and next buttons carry aria-controls too, as a best practice, naming the element that wraps the slides.
In a conventional carousel, the picker, when there is one, is a set of slide buttons, so it carries none of the tab relationships.
aria-controls
In a tabbed carousel, each tab's aria-controls names the one slide it shows. The previous and next buttons act on the whole set, so their aria-controls names the element wrapping the slides rather than any single slide.
Controls a single slide
Reported as: Aria-controls has multiple targets
A tab's aria-controls should reference the one slide it shows.
When the attribute lists several slides, the tab claims to control all of them, and screen reader users can't tell which slide it shows.
Point each tab's aria-controls at its own slide.
Severity: Minor
References valid aria-controls
Reported as: Invalid aria-controls reference
A tab's aria-controls must reference a slide that exists in the document.
When the id is misspelled, belongs to a slide that was replaced, or names a slide that hasn't loaded yet, assistive technology finds no target. Screen reader users who rely on aria-controls can't move from the tab to its slide.
Generate the tab's aria-controls and the slide's id from the same source, and keep them in step as slides are added or removed.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Sets aria-controls
Reported as: Missing aria-controls attribute
Every tab in a picker must have aria-controls set to the id of its slide.
When nothing connects a tab to its slide, the relationship exists only on screen. Assistive technology can't convey which slide the tab shows, so screen reader users have to search for what changed.
Add aria-controls to each tab, with the unique id of the slide it shows.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
aria-owns
A carousel puts its controls before its slides in the DOM and uses CSS when the design shows them somewhere else, such as arrows over the slide or dots below it. Nothing in a carousel needs aria-owns, including to reorder its parts.
The automatic-rotation control, the previous and next buttons, and the picker's tabs have presentational children, so none of them owns anything.
Avoids aria-owns
Reported as: Avoid aria-owns
General check. Evinced checks that the carousel, its controls, and its picker don't use aria-owns to claim elements elsewhere in the document as their children. This check runs on every UI pattern, not only on carousels.
A carousel should hold its controls, picker, and slides in its container in the DOM rather than own them with aria-owns.
When aria-owns moves the controls ahead of the slides, or attaches slides rendered elsewhere, focus still follows the DOM. Screen reader users hear the parts in one order and reach them with the Tab key in another, and assistive technology that doesn't honor the attribute reports those parts outside the carousel.
Render every part inside the carousel's container, with the controls before the slides, and position them with CSS. When a framework portals part of the carousel, portal the whole carousel instead.
Owns only conforming roles
Reported as: Invalid aria-owns values
General check. Evinced checks that every element a tabbed carousel's picker claims with aria-owns has the tab role. This check runs on several UI patterns.
When a picker's tablist uses aria-owns, each element it references should have the tab role.
When an owned element has another role, such as the previous or next button, the tablist's structure no longer adds up. The tab count and positions stop matching the slides, and the arrow keys can reach elements that aren't tabs.
Reference only tabs, and own each tab from one tablist.
Operation
Users operate a carousel with its buttons. With a pointer, clicking previous or next changes the slide, and clicking an automatic-rotation control stops or restarts automatic rotation. With a keyboard, the Tab key and Shift + Tab move through the carousel's controls in DOM order, and Enter or Space activates the one with focus. Focus stays on the button, so users can press it again.
In a tabbed carousel, the picker is a single tab stop. The Tab key reaches the tab for the slide on screen, the Left Arrow and Right Arrow keys move between tabs and show each tab's slide, and Home and End move to the first and last tabs.
A carousel that rotates automatically stops its rotation when keyboard focus moves to any of its elements other than the automatic-rotation control, and doesn't start again until users activate that control. It also pauses while a pointer is over it.
Movement that starts on its own and lasts longer than five seconds has to be stoppable (2.2.2 Pause, Stop, Hide - A), and the automatic-rotation control is how users stop it, including screen reader users whose reading doesn't move focus.
When users have asked their system to reduce motion, the carousel doesn't start rotating automatically on page load. The prefers-reduced-motion media feature reports that setting. For a carousel that checks it, see the conventional carousel under Examples.
Focus Sequence
Inside a carousel, the controls come before the content of the slides on screen, and an automatic-rotation control, when there is one, should be the first tab stop. Slides that are hidden add no tab stops. A tabbed carousel's picker adds a single stop, while slide buttons add one for each slide.
In a tabbed carousel, the element wrapping the slides can also be a tab stop when a slide doesn't start with a focusable element.
Reachable with the Tab key
Reported as: Composite not in focus sequence
A tabbed carousel's picker must have one of its tabs in the tab order.
When every tab has tabindex="-1", or the tabs are generic elements with no tabindex, the Tab key passes over the picker. Keyboard users can't reach any tab, and the arrow keys only work once a tab has focus.
Set tabindex="0" on the tab for the slide on screen and tabindex="-1" on the others. Set the tab stop when the carousel first renders.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Reachable by keyboard
Reported as: Keyboard accessible
Each of a carousel's controls must be in the tab order while it's enabled: previous, next, each slide button, and the automatic-rotation control.
When a control is built from a <div> or <span> without tabindex, pointer users can click it, but keyboard users can't reach it. An automatic-rotation control they can't reach leaves them unable to stop the slides.
Use a <button> element for every control. A custom control needs tabindex="0" along with role="button" and handlers for Enter and Space.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Lands on the selected tab
Reported as: Composite unpredictable focus
When focus enters a picker, it must land on the tab for the slide on screen.
When tabindex="0" stays on the first tab after the carousel moves to another slide, screen reader users arriving with the Tab key hear the first tab as though its slide were the one on screen.
Move tabindex="0" to the tab for the new slide each time the slide changes, including after previous, next, and automatic rotation, and set tabindex="-1" on the tab that had it.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Keeps hidden slides out of tab order
Reported as: Inactive tab panel focusable
A slide that isn't on screen must be out of the tab order.
When slides are hidden with opacity: 0 or off-screen positioning, the links and buttons inside them stay in the tab order. The Tab key stops on content nobody can see, the focus indicator disappears from view, and screen reader users hear a slide that isn't on screen.
Hide the slides that aren't on screen with the hidden attribute or display: none, which takes their content out of the tab order. When a transition keeps a slide rendered, give it the inert attribute until it's hidden.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.4.11 Focus Not Obscured (Minimum) (AA) | When a user interface component receives keyboard focus, the component is not entirely hidden due to author-created content. |
Gives its tabs a single tab stop
Reported as: Redundant focusable children
A tabbed carousel's picker must put no more than one tab in the tab order, with the arrow keys reaching the rest.
When every tab is a <button> with no tabindex="-1", the Tab key stops on every tab, and users press Tab once per slide to get past the picker. The tabs also read as separate controls rather than one set.
Set tabindex="0" on the tab for the slide on screen and tabindex="-1" on the others, and move the tabindex="0" as the slide changes.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Makes the shown slide reachable
Reported as: Tabpanel not focusable
The slide on screen should be reachable with the Tab key from the picker.
When the slide holds only text and images and nothing around it has a tabindex, the Tab key moves from the picker past the slide to whatever follows the carousel. Keyboard users can pick a slide and never reach its content.
Set tabindex="0" on the element wrapping the slides, unless the slide starts with a focusable element.
Severity: Moderate
Puts the automatic-rotation control first
Reported as: Pause mechanism
A carousel's automatic-rotation control should be the first element inside it that the Tab key reaches.
When it comes after the picker or below the slides, keyboard users tab past content that keeps changing before they can stop it, and screen reader users reading from the top meet the moving slides first.
Place the automatic-rotation control first in the carousel's DOM, and position it with CSS if the design shows it elsewhere. Don't use a positive tabindex to move it.
Severity: Minor
Leaves the tab order or reports disabled
Reported as: Disabled element focusable
A carousel control that looks disabled should either leave the tab order or tell users it's disabled.
When a previous or next button at the end of a carousel that doesn't wrap is only styled as disabled, or a custom one keeps tabindex="0" with no disabled state, keyboard users land on a control that does nothing, and screen reader users aren't told why.
Use the disabled attribute on a native button to take it out of the tab order, or aria-disabled="true" to keep it there and report it as unavailable, never both.
Severity: Minor
Element that carries role receives focus
Reported as: Focusable offset
The element that carries a carousel control's button role must be the element that receives focus, not an element inside or around it.
When focus lands on an inner <span> or icon while the role and the handlers sit on its parent, keyboard users can tab to the control, but Enter and Space may do nothing, and assistive technology may not report it as a button.
Put the role, the name, tabindex="0", and the key handlers on one element, or use a <button> element.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Keyboard Navigation
The arrow keys move between the tabs of a tabbed carousel's picker, and moving to a tab shows its slide. The previous and next buttons and the automatic-rotation control are separate tab stops that don't respond to the arrow keys.
As well as the focus indicator on the focused tab, show an indicator around the whole picker while any tab has focus, so sighted keyboard users can tell it's operated with the arrow keys.
Keeps aria-activedescendant valid
Reported as: Missing active descendant
When a picker manages focus with aria-activedescendant rather than a roving tabindex, the attribute must hold the id of the focused tab and change each time focus moves.
When the attribute keeps the value it had at setup, or names an id that no longer exists, the visible highlight moves but screen reader users hear the old tab, or none, and pick a slide they didn't mean to.
Give every tab a unique id, and update aria-activedescendant in the same step that moves the highlight, each time an arrow key, Home, or End is pressed, and on a click.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Moves focus with the arrow keys
Reported as: Focus not updated with arrow keys
The Right Arrow and Left Arrow keys must move focus to the next and previous tab in a horizontal picker, and the Down Arrow and Up Arrow keys must do so in a vertical one.
When the tabs answer only clicks, an arrow key scrolls the page and focus stays where it was. Keyboard users can reach only the tab for the slide on screen, so the picker can't take them to any other slide.
Handle the arrow keys on the tablist, move focus one tab per press, and call preventDefault so the page doesn't scroll.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Keeps focus after selection
Reported as: Focus management on tab select
Selecting a tab must leave focus on that tab or move it to the slide the tab shows.
When selecting a tab re-renders the picker, the focused element is replaced and focus falls back to the top of the page. Screen reader users lose their place in the carousel and don't hear the slide that just appeared.
Keep focus on the selected tab. When selection re-renders the tabs, restore focus once the new markup is in place.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.2 Meaningful Sequence (A) | When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically determined. |
| EN 301 549 | 9.1.3.2 Meaningful Sequence | Same as the WCAG text. |
Moves focus with Home and End
Reported as: Focus not updated with Home or End keys
The Home key must move focus to the first tab in a picker and the End key to the last.
When only the arrow keys are handled, Home and End scroll the page instead, and reaching the last slide's tab takes one key press per slide, each announced by a screen reader.
Handle Home and End on the tablist, move focus the same way the arrow keys do, and call preventDefault so the page doesn't scroll.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Wraps focus at the ends
Reported as: Arrow key navigation loop failed
From the last tab, the forward arrow key should move focus to the first tab, and from the first, the backward arrow key should move it to the last.
When focus stops at either end, a key press does nothing, which looks the same as a picker whose keyboard support has stopped working. Users press again rather than reversing direction.
When users press the Right Arrow key on the last tab, or the Down Arrow key in a vertical picker, move focus to the first tab, and mirror that from the first tab with the Left Arrow or Up Arrow key. Keep focus inside the tablist.
Severity: Minor
Matches arrow keys to orientation
Reported as: Arrow key navigation failed
Sanity check. Evinced checks that the arrow keys matching the picker's orientation move focus from one tab to the next. This check runs on several UI patterns.
A picker's arrow keys should match its layout: the Left Arrow and Right Arrow keys for a row of tabs, such as dots below the slide, and the Up Arrow and Down Arrow keys for a column of thumbnails beside it.
When a vertical picker answers only the Left Arrow and Right Arrow keys, the keys that match what's on screen do nothing, and users conclude the tabs have no keyboard support.
Handle the pair of keys that matches the layout and the aria-orientation value, and leave the other pair to scroll the page.
Manages focus across every tab
Reported as: Skipping composite arrow key navigation
Sanity check. Evinced checks that the arrow keys reach every tab in the picker without skipping any. This check runs on several UI patterns.
Every tab in a picker should be able to take focus in turn, not just the first few.
When a roving tabindex covers only some tabs, such as those rendered before more slides loaded, the arrow keys stall partway along the picker, and the slides past the gap are out of its reach.
Apply one focus method to every tab, and generate it from the same list that renders the slides, so a slide added later gets a working tab.
Unreachable Group
The tab for the slide on screen is the picker's tab stop. When the carousel rotates automatically, or users press previous or next, the script that selects the new slide's tab also moves tabindex="0" to it, so the Tab key never lands on the tab of a hidden slide or finds no tab at all.
Keeps the selected tab reachable
Reported as: Unreachable group
The tab for the slide on screen must be able to take keyboard focus.
When that tab has the disabled attribute, or carries tabindex="-1" while no other tab has tabindex="0", the Tab key passes over the picker. Keyboard users can't reach any tab, including the one marked as selected.
Never disable the tab for the slide on screen, and keep tabindex="0" on it as the slide changes.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Keyboard Activation
Every carousel control activates with Enter or Space while it has focus: previous, next, each slide button, and the automatic-rotation control. A native <button> does this on its own, and a control built from another element needs script for both keys.
Operable by keyboard
Reported as: Button not activated by keyboard
Keyboard users must be able to activate each of a carousel's buttons.
When a control built from a <div> or <span> handles only click, keyboard users can reach it but not use it. When that control is the automatic-rotation control, they can't stop the slides from moving.
Use a <button> element for every control, as the examples do. Otherwise, add key handlers that run the same action as a click: Enter on keydown and Space on keyup.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Ignores keyboard when disabled
Reported as: Disabled button keyboard activation
A carousel button that reports itself as disabled should reject keyboard activation.
When a previous or next button at the end of a carousel that doesn't wrap carries aria-disabled="true" but Enter or Space still runs its action, screen reader users are told the button is unavailable and then find the slide changed. They can't trust either signal.
Check aria-disabled at the start of the handler and return without acting. A native <button> with the disabled attribute ignores activation with no extra code.
Severity: Serious
Activates with Enter and Space
Reported as: Button requires space key activation
A custom carousel control must activate with the Space key, as a <button> element does, not just with Enter.
When only Enter works, users who press Space, as they would on any other button, find the control unresponsive and may conclude the slides can't be moved or stopped.
Add a Space keyup handler that runs the control's action, or use a native <button> element.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Selected Tabs
A tabbed carousel shows one slide at a time, so its picker's tablist never declares multiple selection. Selecting a tab from the keyboard shows that tab's slide, the same as a click does.
Selects from the keyboard
Reported as: No keyboard selection
A tab in a tabbed carousel's picker must be selectable from the keyboard.
When selection is wired only to a click handler on a generic element, keyboard users can move focus to a tab and can't show its slide. Focus moves and the focus indicator shows, so the failure appears only when they try to choose.
Select the focused tab on Enter and Space, or on focus with automatic activation, by calling the same code a click runs. Update aria-selected and show the slide in the same step.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Acts on Space when focused
Reported as: Spacebar does not trigger selection
Pressing Space on a focused tab must select it, unless the tab was selected automatically when it received focus.
When a tab handles Enter and ignores Space, or lets Space scroll the page, keyboard users get no new slide and no error. Most conclude the tab can't be chosen.
Handle Space on the tabs, run the same code a click runs, and call preventDefault so the page doesn't scroll. A <button> with role="tab" fires a click on Space by itself.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Declares multiple selection
Reported as: Aria-multiselectable attribute required
A tabbed carousel's picker must mark only one tab as selected, since the carousel shows one slide at a time.
When several tabs carry aria-selected="true" and the tablist doesn't declare aria-multiselectable, assistive technology reports a list that takes one choice with several chosen, and screen reader users can't tell which slide is on screen.
Set aria-selected="true" on the tab for the slide on screen and "false" on every other tab. Don't add aria-multiselectable: a carousel never has more than one slide selected.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Toggle Activation
Each press of the automatic-rotation control turns automatic rotation on or off, and the control reports the change: a toggle button through aria-pressed with a fixed name, and a command button through its name, as the conventional example's start() and stop() do. A carousel that also stops rotating when focus moves into it changes the state without a press, and the control reports that change too.
Reports a press in state or name
Reported as: Toggle state not updated
The automatic-rotation control must report every press, either through aria-pressed on a toggle button or through the name of a command button.
When a press starts or stops the slides but the control keeps saying the same thing, screen reader users, who may not perceive the movement, can't tell whether rotation is on. They may press again and undo what they meant to do.
Update aria-pressed or the name in the same function that starts and stops rotation, so every route that changes the state reports it.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Updates the state on activation
Reported as: Element's state did not change
Activating an automatic-rotation control that carries aria-pressed, with a pointer or the keyboard, must update aria-pressed to its new state.
When aria-pressed keeps its starting value, assistive technology reports the old state after every press. A screen reader user who stops the rotation is still told it's on.
Set aria-pressed in the code that starts and stops rotation, and handle pointer and keyboard activation through that one code path.
Evinced reports this issue as Critical or as Serious, depending on the context where it shows up.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Returns to its earlier state
Reported as: Toggle state not resetting
Activating the automatic-rotation control twice must return its reported state to where it started.
When a second press leaves the state as it was, or sets yet another value, users can't tell whether the slides are moving, and can't restart rotation they stopped or stop it again.
Set the reported state from whether the carousel is rotating each time that changes, rather than setting it once.
Evinced reports this issue as Critical or as Serious, depending on the context where it shows up.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Changes state or name, not both
Reported as: Toggle button overlapping changes
Activating the automatic-rotation control must change its aria-pressed value or its name, not both.
When the control updates aria-pressed and swaps its name on the same press, screen readers announce contradictions such as "Start slide rotation, pressed", and users can't tell whether rotation is on.
Keep a toggle button's name fixed and let aria-pressed carry the state. If the name has to change, as in the conventional example, remove aria-pressed.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Keeps a stateful name in step
Reported as: Toggle name not resetting
An automatic-rotation control without aria-pressed must change its name every time rotation starts or stops.
When "Stop slide rotation" becomes "Start slide rotation" after the first press and then keeps that name, the control contradicts the carousel. Screen reader users hear "Start" while the slides move.
Set the name from the rotation state each time it changes, as start() and stop() do in the conventional example.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Ignores activation when disabled
Reported as: Disabled element active
An automatic-rotation control that presents as disabled must not start or stop rotation when it's activated.
When the control is styled as unavailable, or carries aria-disabled="true", but its handlers still run, users are told it isn't available and then find the slides started or stopped.
Check the disabled state at the start of the handler and return without acting, on both the pointer and keyboard paths. A native <button> with the disabled attribute blocks activation with no extra code.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Event Listener Type
When script in a carousel responds to keys, it listens for keydown or keyup. The keypress event is deprecated, and browsers don't fire it for many keys, including the arrow keys, Home, End and Escape.
Avoids the keypress event
Reported as: Deprecated keypress listener
A carousel's key handling should use keydown or keyup, not keypress.
When a handler listens for keypress, keys the browser doesn't send through that event go unanswered, and keyboard users find the carousel ignoring keys it's meant to respond to.
Replace each keypress listener with a keydown listener, and read the key from event.key.
Severity: Minor
FAQ
Which WCAG success criteria do the carousel issues relate to?
Most relate to 4.1.2 Name, Role, Value or 1.3.1 Info and Relationships. 4.1.2 Name, Role, Value covers the container's, picker's, and tabbed slides' roles, the names of slides, tabs, and buttons, the selected tab, disabled states, keeping controls out of buttons and tabs, the automatic-rotation control's state and how it reports each press, the live region during automatic rotation, and the buttons at the first and last slides.
1.3.1 Info and Relationships covers the tab role, the carousel's name, exposing and displaying the slide on screen, set sizes and positions, aria-controls, a single tab stop for the picker, aria-activedescendant, and a disabled automatic-rotation control that still responds.
Reaching and activating the carousel's buttons, and reaching, selecting, and moving between the picker's tabs, relate to 2.1.1 Keyboard. Showing the automatic-rotation control's state by more than color relates to 1.4.1 Use of Color, and a way to stop automatic rotation to 2.2.2 Pause, Stop, Hide. Announcing a slide change users make relates to 4.1.3 Status Messages, keeping focus after a selection to 1.3.2 Meaningful Sequence, and keeping hidden slides out of the tab order to 2.4.11 Focus Not Obscured (Minimum).
The role descriptions, distinct names, a single live region, the controls themselves, an automatic-rotation control placed first, wrapping focus, and disabled buttons that leave the tab order or ignore the keyboard are among the best practices that map to no WCAG success criterion.
Why are some carousel issues marked as Critical and others as Minor?
Severity reflects how much an issue gets in users' way. Critical issues stop users outright: a container with no role, unnamed slides or tabs, no selected tab, a slide on screen that isn't displayed or exposed, tabs keyboard users can't reach, select, or move through, unnamed buttons, buttons keyboard users can't reach or activate, or an automatic-rotation control that doesn't report its state after a press.
Serious issues confuse users though tasks are still possible, such as duplicate names, mixed picker roles, no announcement of a slide change, no way to stop automatic rotation, no controls, hidden slides left in the tree or the tab order, a wrong disabled state, a disabled button that still responds to keys, a rotation state shown by color alone, or an automatic-rotation control that changes both its state and its name, or stops changing its name.
Moderate issues include a missing role description, an unnamed tabbed slide, several live regions, buttons that neither wrap nor report the end, set counts that can't be true, an undefined aria-pressed value, and a disabled automatic-rotation control that still responds.
Minor issues are mostly an unnamed carousel, attributes set in the wrong place, redundant words in names and role descriptions, an automatic-rotation control that isn't first, controls that respond only to Enter, a disabled control left in the tab order without saying so, and focus that lands inside a control rather than on it.
The aria-owns checks and the checks on where roles sit and on arrow-key focus carry no severity: Evinced reports them as general and sanity checks.
Related Patterns
- Tablist: the picker of a tabbed carousel, and the pattern for choosing labeled sections in any order
- Accordion: stacked sections of content that users expand one or more at a time
Recommended Reading
- Carousel (Slide Show or Image Rotator) Pattern | W3C ARIA Authoring Practices Guide
- Carousels Tutorial | W3C Web Accessibility Initiative
aria-roledescriptionproperty | W3C WAI-ARIA- A Step-By-Step Guide To Building Accessible Carousels | Smashing Magazine
- How to Test and Improve Carousel Accessibility: A Complete Guide | The A11y Collective