How to build an accessible Carousel in React

A section with aria-roledescription="carousel" holding one role="group" per slide. Inactive slides are `inert`, not `aria-hidden`: they stay in the layout and remain scroll-reachable, so aria-hidden alone declared them non-existent to assistive technology while every link and button inside them was still tabbable — the canonical aria-hidden-focus violation. The track is aria-live="polite" when the user drives the carousel and "off" while it rotates on its own, per APG; a rotating carousel always renders a play/pause control, and rotation additionally pauses on hover, on focus within, while the tab is hidden and under prefers-reduced-motion. Reduced motion is read in JS as well as CSS because a scrollTo `behavior` option overrides the stylesheet, which is why the previous build's stylesheet rule could never take effect. Arrow keys on the indicator row move the slide, not merely the roving tabindex, and the indicators are named as their own group rather than repeating the region's name. The indicator hit area reaches the target minimum through a pseudo-element, leaving the 10px visual mark unchanged.

When to use a Carousel

When not to use it

Keyboard interactions

Role group, verified at WCAG 2.2-AA.

Common mistakes

Avoid: Auto-rotating carousel for primary navigation or key calls-to-action

Prefer: A static list or grid where every item is visible

Auto-rotation and hidden slides reduce discoverability and accessibility of important content

Example

<Carousel>
  <img src="/1.jpg" alt="" />
  <img src="/2.jpg" alt="" />
</Carousel>

See the full Carousel reference →