Carousel
| Severity | Serious |
|---|---|
| Accessibility Principle | Operable |
| Affected users | Visual, Motor |
| Success criterion | 2.3.3 |
A carousel displays a series of items one at a time, where users swipe left or right to move between them. For screen reader users, the standard swipe gesture conflicts with how they navigate the screen — so a carousel must expose increment and decrement accessibility actions instead, using the adjustable role to signal this to the screen reader.
Expectations
- When: The user focuses a Carousel component
- Then: The Screen Reader announces: [Component label] Adjustable/Slider, swipe up or down to adjust
- When: User swipes up
- Then: The previous item is focused
- When: User swipes down
- Then: The next item is focused
- When: User swipes up
- Then: The Screen Reader announces: [Component label] Adjustable/Slider, swipe up or down to adjust
| VoiceOver | Talkback |
|---|---|
| [Component label], Adjustable, swipe up or down with one finger to adjust the value | [Component label], Slider, swipe up or swipe down to adjust |
When the Screen Reader is activated, navigation typically relies on specific gestures to interact with content:
- 1-finger swipe up: This gesture usually focuses on the next item
- 1-finger swipe down: This gesture focuses on the previous item
- When: The user pronounces the carousel label
- Then: Voice Control highlights the carousel
- And:
- The user can then issue swipe gestures verbally ("swipe left", "swipe right") to advance between items
- And:
- Then: Voice Control highlights the carousel
Example
To implement this navigation behavior in React Native when the Screen Reader is on, we need to:
- use the accessibility role adjustable
- set
accessibilityActions={[{ name: 'increment' }, { name: 'decrement' }]} - handle onAccessibilityAction to change the index
<FlatList
ref={flatList}
data={data}
renderItem={renderItem}
accessible={true}
accessibilityLabel="Carousel"
accessibilityRole="adjustable"
accessibilityActions={[{ name: 'increment' }, { name: 'decrement' }]}
onAccessibilityAction={(event: AccessibilityActionEvent) => {
const value = event.nativeEvent.actionName === 'increment' ? 1 : -1;
const newIndex = carouselIndexForScreenReader.current + value;
carouselIndexForScreenReader.current = clamp(newIndex, 0, data.length - 1);
flatList.current?.scrollToIndex({
index: carouselIndexForScreenReader.current,
});
}}
/>
Best Practices
Use the adjustable role with increment/decrement actions
The adjustable role tells the screen reader that swipe-up/down adjusts a value. Without it, the user has no indication that the carousel can be navigated at all.
accessibilityRole="adjustable"
accessibilityActions={[{ name: 'increment' }, { name: 'decrement' }]}
Announce the current position
Include the item's position in its label or hint so the user knows where they are in the sequence.
accessibilityLabel={`Carousel, item ${currentIndex + 1} of ${data.length}`}
Provide a way to pause auto-advancing carousels
If the carousel advances automatically, include a pause or stop control. Auto-advancing content that cannot be paused fails WCAG 2.2.2 Pause, Stop, Hide.