apx-dsv0.1Local renderer · live
K
Foundations4
  • Getting started
  • Theming
  • Templates
  • Icons
  • Avatar
  • Badge
  • DataGrid
  • Scheduler
  • Stat
  • Table
  • Timeline
  • TreeView
  • Accordion
  • Alert
  • EmptyState
  • Progress
  • Skeleton
  • Spinner
  • SplashScreen
  • Toast
  • ColorPicker
  • FileUpload
  • Form
  • Rating
  • TagsInput
  • Combobox
  • Field
  • Select
  • Toggle
  • Button
  • Calendar
  • Checkbox
  • DatePicker
  • Input
  • NumberInput
  • Radio
  • Slider
  • Switch
  • Textarea
  • AppShell
  • Div
  • Divider
  • Sidebar
  • Stack
  • Typography
  • Image
  • Breadcrumbs
  • Carousel
  • NavigationMenu
  • Pagination
  • Stepper
  • Tabs
  • Toolbar
  • CommandPalette
  • Confirm
  • Drawer
  • HoverCard
  • Menu
  • Modal
  • Popover
  • Tooltip
  • Icon
  • Card
  • PricingCard
60 componentsapx-ds/renderer
Carousel
Variant↳ other

Navigation

Carousel

Accessible, keyboard- and touch-friendly carousel powered by CSS scroll-snap with a thin JS coordination layer. Zero new dependencies (no Embla / Swiper). Autoplay off by default; when enabled, always-visible pause/play (WCAG 2.2.2). Horizontal + vertical, responsive

Overview

<Carousel /> is an accessible, keyboard- and touch-friendly carousel built on CSS scroll-snap with a thin JS coordination layer for index tracking, controls, and optional autoplay. Zero new runtime dependencies — no Embla, no Swiper.

It ships two equivalent APIs that resolve to the same DOM:

  • Prop-driven (90% case) — drop <Carousel.Slide> children in and the Viewport, Track, Controls, and Indicators are auto-wrapped for you.
  • Compound (power users) — render the full <Carousel.Viewport> / <Carousel.Track> / <Carousel.Slide> shape yourself for precise layout control.

Overview — image gallery with arrows and dots

Loading preview…
Overview.tsx

Anatomy

SubpartElementRole
<Carousel><section role="region">landmark + CarouselContext provider
<Carousel.Viewport><div tabIndex={0}>overflow scroll container; main keyboard target
<Carousel.Track><div data-carousel-track>flex container of slides; owns inter-slide gap
<Carousel.Slide><div role="group"> (or asChild)one slide; auto-labeled "Slide N of M"
<Carousel.Controls><div data-carousel-controls>wrapper for Prev / Next buttons (overlay / top / bottom)
<Carousel.PrevButton><button>step backwards by one slide
<Carousel.NextButton><button>step forwards by one slide
<Carousel.Indicators><div role="tablist">dot/bar/number indicators row
<Carousel.Indicator><button role="tab">one indicator targeting a specific slide
<Carousel.AutoplayControl><button aria-pressed>visible play/pause toggle when autoplay is enabled (WCAG 2.2.2)
<Carousel.LiveRegion><div aria-live> (sr-only)announces slide changes when explicit / autoplay paused

Examples

Basic

Loading preview…
Basic.tsx

HeroBanner

Loading preview…
HeroBanner.tsx

ProductLane

Loading preview…
ProductLane.tsx

Responsive

Loading preview…
Responsive.tsx

Vertical

Loading preview…
Vertical.tsx

Loop

Loading preview…
Loop.tsx

Autoplay

Loading preview…
Autoplay.tsx

AutoplayPauseOnHover

Loading preview…
AutoplayPauseOnHover.tsx

ControlledIndex

Loading preview…
ControlledIndex.tsx

ProgrammaticRef

Loading preview…
ProgrammaticRef.tsx

SnapCenter

Loading preview…
SnapCenter.tsx

SnapNone

Loading preview…
SnapNone.tsx

CustomIndicators

Loading preview…
CustomIndicators.tsx

PolymorphicSlides

Loading preview…
PolymorphicSlides.tsx

WithCardContent

Loading preview…
WithCardContent.tsx

WithFadeShadows

Loading preview…
WithFadeShadows.tsx

ImageGallery

Loading preview…
ImageGallery.tsx

TestimonialCarousel

Loading preview…
TestimonialCarousel.tsx

Props

PropTypeDefaultNotes
orientation'horizontal' | 'vertical''horizontal'Scroll axis.
slidesPerViewResponsiveValue<number>1How many slides are visible at once.
gapResponsiveValue<number>0Inter-slide gap in 4px theme spacing units (i.e. 3 ⇒ 12px).
snap'start' | 'center' | 'end' | 'none''start'CSS scroll-snap alignment per slide.
index / defaultIndexnumber0Controlled / uncontrolled active index.
onIndexChange(index, source) => void—Fires on any change. source ∈ keyboard / control / indicator / autoplay / scroll / programmatic.
loopbooleanfalseWrap-around navigation past the last slide back to the first.
autoplaybooleanfalseOff by default (WCAG 2.2.2).
autoplayIntervalnumber5000Tick interval in ms.
autoplayDirection'forward' | 'backward''forward'Direction of auto-advance.
pauseOnHoverbooleantruePause while the pointer hovers the viewport.
pauseOnFocusbooleantruePause while anything inside the viewport is focused.
pauseOnReducedMotionbooleantruePause when prefers-reduced-motion: reduce.
showAutoplayControl'auto' | 'always' | 'never''auto'Visibility of the play/pause button (always visible when autoplay enabled).
showControls'auto' | 'always' | 'never''auto'Visibility of Prev/Next buttons.
showIndicators'auto' | 'always' | 'never''auto'Visibility of the indicators row.
ariaLabelstring'Carousel'Required accessible name for the region (defaults to "Carousel").
ariaLabelledbystring—Alternative to ariaLabel — id of an external labeling element.
ariaRoleDescriptionstring'carousel'aria-roledescription. Common overrides: 'gallery', 'banner'.
liveRegionPoliteness'off' | 'polite''off'When 'polite', slide changes announce to assistive tech.
variant'default' | 'ghost' | 'card''default'Root container styling.
size'sm' | 'md' | 'lg''md'Drives indicator + button sizing.
showShadowsbooleanfalseFade gradients on the leading + trailing scroll edges.
scrollBehavior'smooth' | 'auto''smooth'Programmatic scroll behavior (prefers-reduced-motion collapses smooth → auto).

Imperative ref

tsx
const ref = useRef<CarouselRef>(null);

ref.current?.scrollTo(2);
ref.current?.next();
ref.current?.prev();
ref.current?.getIndex();
ref.current?.getSlideCount();
ref.current?.isAutoplaying();
ref.current?.pauseAutoplay();
ref.current?.playAutoplay();
const ref = useRef<CarouselRef>(null);

ref.current?.scrollTo(2);
ref.current?.next();
ref.current?.prev();
ref.current?.getIndex();
ref.current?.getSlideCount();
ref.current?.isAutoplaying();
ref.current?.pauseAutoplay();
ref.current?.playAutoplay();

Keyboard

Focus the <Carousel.Viewport> (Tab into it) — then:

KeyHorizontal (LTR)Horizontal (RTL)Vertical
ArrowLeft / ArrowRightprev / nextnext / prev—
ArrowUp / ArrowDown——prev / next
PageUp / PageDownprev / nextprev / nextprev / next
Home / Endfirst / lastfirst / lastfirst / last
Spacetoggle autoplay (only when autoplay is enabled)——

Prev / Next buttons and Indicators are in the standard Tab order; the Viewport itself is also focusable for power keyboard users who want to skip the controls.

Accessibility

  • Root is a <section role="region"> with a required aria-label (default 'Carousel') and aria-roledescription="carousel".
  • Each slide is a role="group" with aria-roledescription="slide" and an auto-generated aria-label="Slide N of M".
  • Indicators render as role="tab" inside a role="tablist", with aria-selected + aria-current.
  • Autoplay is off by default (WCAG 2.2.2). When enabled, the <Carousel.AutoplayControl> is rendered automatically and gives the user a visible pause/play toggle. Autoplay also pauses when the user hovers / focuses the carousel, when prefers-reduced-motion: reduce is set, when the tab is backgrounded, and when the user has explicitly paused via the button.
  • A live region (<Carousel.LiveRegion>) is rendered when liveRegionPoliteness="polite" or whenever the user pauses autoplay; it announces "Slide N of M" on manual navigation only, never during autoplay (to avoid AT spam).
  • Loop wrap-around uses programmatic scrollTo; no DOM clones means screen readers always see the real slide list once.

RTL

Direction is read from useDirection(). ArrowLeft / ArrowRight semantics flip automatically for horizontal carousels; vertical and PageUp / PageDown remain direction-neutral. The Prev / Next chevron glyphs mirror automatically.

i18n

Strings are English defaults with prop overrides:

  • ariaLabel (region)
  • ariaRoleDescription (region)
  • <Carousel.Slide ariaLabel> (per-slide override)
  • <Carousel.PrevButton ariaLabel> (default 'Previous slide')
  • <Carousel.NextButton ariaLabel> (default 'Next slide')
  • <Carousel.AutoplayControl ariaLabelPlay / ariaLabelPause> (defaults 'Play carousel' / 'Pause carousel')
  • <Carousel.Indicators renderLabel> callback (index, total) => string

Once <I18nProvider> lands, these will default to provider-supplied strings; the prop overrides will remain higher precedence.

Theming

The full recipe matrix (root, viewport, track, slide, controls, controlButton, indicators, indicator) is exposed through theme styleOverrides.Carousel so brands can restyle every slot without forking the source.

Do / Don't

Do

  • Use a single <Carousel> per region; if you have many lanes on a page, give each a unique ariaLabel so AT users can tell them apart.
  • Provide an accessible name for image-only slides via <Carousel.Slide ariaLabel> (image galleries lean on this).
  • Use loop for hero banners, leave it off for content lanes (otherwise the keyboard order loops infinitely).
  • Use slidesPerView with a responsive object ({ base: 1, md: 3 }) — let small screens show one slide.

Don't

  • Don't enable autoplay without a visible pause/play control (the component does this for you; the AutoplayControl renders automatically).
  • Don't put critical actions inside autoplaying slides — users won't have time to click.
  • Don't disable pauseOnReducedMotion; users have set this preference explicitly.
  • Don't nest a <Carousel> inside another <Carousel> — the keyboard semantics conflict.

Props

PropTypeDefaultDescription
ariaLabelstring—Required accessible name for the region. Pair with `ariaLabelledby` if labeling another element.
ariaLabelledbystring—Alternative to `ariaLabel`: id of an element labeling the carousel region.
ariaRoleDescriptionstring—`aria-roledescription` for the region. Default `'carousel'`. Common overrides: `'gallery'`, `'banner'`.
autoplayboolean—Enables interval-based auto-advance. **OFF by default** (WCAG 2.2.2).
autoplayDirectionenum—Direction the autoplay advances. Default `'forward'`.
autoplayIntervalnumber—Autoplay interval in ms. Default `5000`.
childrenReactNode—Carousel children — usually `<Carousel.Slide>` elements (auto-wrapped) or the full compound shape.
classNamestring——
defaultIndexnumber—Uncontrolled initial index. Default `0`.
gapResponsiveValue<number>—Inter-slide gap in the theme spacing scale. Default `0`.
indexnumber—Controlled active-slide index.
liveRegionPolitenessenum—Politeness of the live region announcing slide changes. Default `'off'`.
loopboolean—Enables wrap-around navigation past the last slide back to the first. Default `false`.
onIndexChange(index: number, source: CarouselChangeSource) => void—Fires whenever the active slide changes.
orientationenum—Orientation of the scroll axis. Default `'horizontal'`.
pauseOnFocusboolean—Pause the autoplay while any element inside the carousel is focused. Default `true`.
pauseOnHoverboolean—Pause the autoplay while the pointer hovers over the carousel. Default `true`.
pauseOnReducedMotionboolean—Pause the autoplay when `prefers-reduced-motion: reduce`. Default `true`.
refRef<CarouselRef>—Imperative handle. Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
scrollBehaviorenum—`scroll-behavior` for programmatic scrolls. `prefers-reduced-motion` auto-converts smooth → auto.
showAutoplayControlenum—When to render the visible pause/play control. Default `'auto'` (when autoplay enabled).
showControlsenum—When to render the Prev/Next buttons. Default `'auto'` (only when scrolling is possible).
showIndicatorsenum—When to render the Indicators row. Default `'auto'`.
showShadowsboolean—Adds fade gradients on the leading + trailing scroll edges. Default `false`.
sizeenum—Visual size scale; controls indicator + button sizing. Default `'md'`.
slidesPerViewResponsiveValue<number>—Number of slides visible at once. Accepts a responsive value. Default `1`.
snapenum—Scroll-snap alignment per slide. Default `'start'`.
styleCSSProperties——
sxSx——
variantenum—Visual variant of the root container. Default `'default'`.