Vize

Carousel

Headless WAI-ARIA carousel on native scroll snapping, with autoplay, drag, and slide picker.

Package @vizejs/ui/carousel
Maturity stable
Own the source vize lib pull carousel
Requires context, controllable-state, id, measure
Aliases carousel, slider gallery, slideshow, image carousel, content rotator
Covers WAI-ARIA Carousel, CSS Scroll Snap, Ark UI Carousel, Embla Carousel, shadcn/ui Carousel

Usage

import { CarouselAutoplayToggle, CarouselIndicator, CarouselIndicatorGroup, CarouselNext, CarouselPrevious, Carousel, CarouselRoot, CarouselSlide, CarouselViewport } from "@vizejs/ui/carousel";

Or copy the source into your project with vize lib pull carousel (see Source Distribution).

API

CarouselAutoplayToggle

Source: src/families/media/carousel/carousel-autoplay-toggle.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name for icon-only controls. Prefer slot text that changes with the state, e.g. "Stop slide rotation" / "Start slide rotation".

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before toggling. Call preventDefault() to keep the rotation intent.

Slots

Slot Slot props Description
default CarouselSlotState Control label. Receives the carousel state; autoplay tells which label to show.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

CarouselIndicator

Source: src/families/media/carousel/carousel-indicator.vue

Props

Prop Type Default Description
index (required) number required Zero-based slide index this indicator activates.
ariaLabel string undefined Accessible name. Defaults to "Slide index + 1" when the slot renders no text.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before activation. Call preventDefault() to keep the active slide.

Slots

Slot Slot props Description
default CarouselIndicatorSlotState Indicator content, e.g. a dot or thumbnail. Receives its activity state.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

CarouselIndicatorGroup

Source: src/families/media/carousel/carousel-indicator-group.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name of the slide picker, e.g. "Choose slide".
ariaLabelledby string undefined Space-separated ids that label the slide picker.

Slots

Slot Slot props Description
default CarouselSlotState CarouselIndicator children. Receives the carousel state.

Exposed

Member Type Description
element HTMLDivElement | null Rendered tablist element.

CarouselNext

Source: src/families/media/carousel/carousel-next.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name for icon-only controls.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before navigation. Call preventDefault() to keep the active slide.

Slots

Slot Slot props Description
default CarouselSlotState Control content. Receives the carousel state.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

CarouselPrevious

Source: src/families/media/carousel/carousel-previous.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name for icon-only controls.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before navigation. Call preventDefault() to keep the active slide.

Slots

Slot Slot props Description
default CarouselSlotState Control content. Receives the carousel state.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

Source: src/families/media/carousel/carousel-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned carousel base id. null and undefined select a deterministic fallback.
slideCount (required) number required Number of slides. Declared up front so slide labels ("2 of 5"), navigation availability, and indicators render correctly on the server.
modelValue number undefined Controlled zero-based active slide index. undefined selects uncontrolled behavior.
defaultValue number 0 Initial active slide for uncontrolled use.
loop boolean false Wrap previous/next navigation and keyboard movement at both ends.
orientation CarouselOrientation "horizontal" Scroll axis of the track.
dir CarouselDirection undefined Reading direction used for horizontal arrow keys and scroll offsets. undefined inherits DirectionProvider/LocaleProvider, then "ltr".
draggable boolean true Let mouse pointers drag the track. Touch and pen swipes always use native scrolling.
autoplay boolean false Initial automatic rotation intent for uncontrolled use.
playing boolean undefined Controlled automatic rotation intent (v-model:playing). undefined selects autoplay.
interval number 5000 Milliseconds each slide stays active while rotating.
pauseOnHover boolean true Pause rotation while a mouse or pen pointer hovers the carousel.
focusBehavior CarouselFocusBehavior "stop" How keyboard focus entering the carousel affects rotation. stop follows the WAI-ARIA carousel pattern and turns rotation off until explicitly restarted.
respectReducedMotion boolean true Pause rotation while prefers-reduced-motion: reduce matches, and scroll without smooth animation.
ariaLabel string undefined Accessible carousel name when no visible heading supplies one.
ariaLabelledby string undefined Space-separated ids that label the carousel.
messages CarouselMessages undefined Localized role descriptions and slide/indicator names. Omitted entries use the English WAI-ARIA example wording.

Events

Event Payload Description
update:modelValue [index: number] Fired when the active slide requests a new controlled index.
change [index: number, previous: number, reason: CarouselChangeReason] Fired after any distinct active-slide request, with its cause.
update:playing [playing: boolean] Fired when rotation intent requests a new controlled value.

Slots

Slot Slot props Description
default CarouselSlotState Viewport, slides, controls, and indicators. Receives the carousel state.

Exposed

Member Type Description
autoplay —
canScrollNext —
canScrollPrev —
dragging —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.
index —
orientation —
play —
scrollNext —
scrollPrev —
scrollTo —
slideCount —
stop —

CarouselRoot

Source: src/families/media/carousel/carousel-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned carousel base id. null and undefined select a deterministic fallback.
slideCount (required) number required Number of slides. Declared up front so slide labels ("2 of 5"), navigation availability, and indicators render correctly on the server.
modelValue number undefined Controlled zero-based active slide index. undefined selects uncontrolled behavior.
defaultValue number 0 Initial active slide for uncontrolled use.
loop boolean false Wrap previous/next navigation and keyboard movement at both ends.
orientation CarouselOrientation "horizontal" Scroll axis of the track.
dir CarouselDirection undefined Reading direction used for horizontal arrow keys and scroll offsets. undefined inherits DirectionProvider/LocaleProvider, then "ltr".
draggable boolean true Let mouse pointers drag the track. Touch and pen swipes always use native scrolling.
autoplay boolean false Initial automatic rotation intent for uncontrolled use.
playing boolean undefined Controlled automatic rotation intent (v-model:playing). undefined selects autoplay.
interval number 5000 Milliseconds each slide stays active while rotating.
pauseOnHover boolean true Pause rotation while a mouse or pen pointer hovers the carousel.
focusBehavior CarouselFocusBehavior "stop" How keyboard focus entering the carousel affects rotation. stop follows the WAI-ARIA carousel pattern and turns rotation off until explicitly restarted.
respectReducedMotion boolean true Pause rotation while prefers-reduced-motion: reduce matches, and scroll without smooth animation.
ariaLabel string undefined Accessible carousel name when no visible heading supplies one.
ariaLabelledby string undefined Space-separated ids that label the carousel.
messages CarouselMessages undefined Localized role descriptions and slide/indicator names. Omitted entries use the English WAI-ARIA example wording.

Events

Event Payload Description
update:modelValue [index: number] Fired when the active slide requests a new controlled index.
change [index: number, previous: number, reason: CarouselChangeReason] Fired after any distinct active-slide request, with its cause.
update:playing [playing: boolean] Fired when rotation intent requests a new controlled value.

Slots

Slot Slot props Description
default CarouselSlotState Viewport, slides, controls, and indicators. Receives the carousel state.

Exposed

Member Type Description
index number Zero-based active slide index.
slideCount number Total number of slides declared on the root.
canScrollPrev boolean Whether previous navigation is available.
canScrollNext boolean Whether next navigation is available.
autoplay CarouselAutoplayState Automatic rotation state.
dragging boolean Whether a pointer drag is moving the track.
orientation CarouselOrientation Scroll axis.
element HTMLElement | null Rendered root element.
scrollTo (index: number) => boolean Activate one slide. Reports whether the active index changed.
scrollNext () => boolean Activate the next slide (wrapping when loop). Reports whether the index changed.
scrollPrev () => boolean Activate the previous slide (wrapping when loop). Reports whether the index changed.
play () => boolean Turn automatic rotation on. Reports whether the intent changed.
stop () => boolean Turn automatic rotation off. Reports whether the intent changed.

CarouselSlide

Source: src/families/media/carousel/carousel-slide.vue

Props

Prop Type Default Description
index (required) number required Zero-based slide position. Must be unique and below slideCount.
ariaLabel string undefined Accessible slide name. Defaults to "index + 1 of slideCount" per the carousel pattern.

Slots

Slot Slot props Description
default CarouselSlideSlotState Slide content. Receives activity and visibility state.

Exposed

Member Type Description
index number Zero-based slide index.
active boolean Whether this slide is the active slide.
inView boolean | null Whether the slide is at least half visible; null until measured on the client.
state CarouselSlideState Stable state token for styling and tests.
element HTMLDivElement | null Rendered slide element.
id string Deterministic slide id.

CarouselViewport

Source: src/families/media/carousel/carousel-viewport.vue

Props

Prop Type Default Description
settleDelay number 120 Quiet period after the last scroll event before a user scroll selects the nearest slide, for browsers without scrollend.
dragThreshold number 40 Pixels a mouse drag must travel to page to the adjacent slide even when the track would snap back to the starting slide.

Slots

Slot Slot props Description
default CarouselSlotState CarouselSlide children. Receives the carousel state.

Exposed

Member Type Description
element HTMLDivElement | null Rendered scroll container.
id string Deterministic id referenced by navigation controls.

Behavior

Normative state x input -> outcome table for carousel-root.vue, carousel-viewport.vue, carousel-slide.vue, carousel-previous.vue, carousel-next.vue, carousel-indicator-group.vue, carousel-indicator.vue, and carousel-autoplay-toggle.vue (@vizejs/ui/carousel). Every row is proven by the named test.

The carousel follows the WAI-ARIA APG carousel pattern on top of native scroll snapping: the viewport is the consumer-styled scroll container, the active index is the source of truth, and the track scrolls to the active slide. User scrolls (touch swipes, trackpads, scrollbars) settle on the nearest slide without being corrected. slideCount and each slide's index are declared so labels, navigation availability, and indicators are correct on the server.

Minimal consumer CSS: [data-vize-ui="carousel-viewport"] { display: flex; overflow: auto; scroll-snap-type: x mandatory } and [data-vize-ui="carousel-slide"] { flex: 0 0 100%; scroll-snap-align: start }.

ID State Input Outcome Evidence
C1 default render section with aria-roledescription="carousel", focusable polite viewport, group/slide slides labelled "n of N", wired controls and tablist renders the carousel pattern with deterministic ids, slide labels, and wired controls
C2 non-looping Previous / Next moves one slide, smooth-scrolls the viewport so the slide aligns with its start edge, and disables the control at each end previous and next move one slide, scroll the track, and stop at the ends
C3 loop Previous at start / Next at end wraps to the other end; a single slide never wraps loop wraps navigation at both ends
C4 controlled modelValue navigation emits the requested index while rendering the controlled index; out-of-range values clamp controlled index wins until the parent accepts the request
C5 indicators click / Arrow / Home / End selects the slide, keeps one roving tab stop on the active indicator, and moves focus with the selection indicators select slides and move roving focus with arrow, Home, and End keys
C6 focused viewport Arrow / Home / End arrows follow orientation and dir; keys from slide content are ignored the focused viewport maps arrow keys by orientation and reading direction
C7 user scroll scroll quiet period or scrollend the slide nearest the viewport start becomes active with reason scroll, without a corrective scroll user scrolling settles on the nearest slide without re-scrolling
C8 programmatic scroll own scrollend / reduced motion initial defaultValue scrolls instantly; programmatic settles are ignored; reduced motion scrolls with behavior: "auto" programmatic scrolls ignore their own settle and respect reduced motion
C9 multiple slides per view scrolled to the end Next disables once the track cannot scroll further scroll edges disable next when multiple slides fill the viewport
C10 mouse drag pointerdown / move / up moves the track with snapping suspended, pages past dragThreshold, re-snaps, and swallows the trailing click; touch and draggable=false skip mouse drags move the track, page past the threshold, and suppress the trailing click
C11 short drag pointer release below the threshold re-aligns to the starting slide without a change event short drags snap back to the starting slide
C12 autoplay playing interval elapses advances with reason autoplay, rewinds after the last slide, and sets the viewport live region to off autoplay advances on an interval, rewinds at the end, and silences the live region
C13 autoplay playing hover / pointer focus / keyboard focus mouse hover pauses; pointer-initiated focus does not stop; keyboard focus stops (focusBehavior="stop") or pauses ("pause"); touch never hovers hover and pointer focus pause rotation while keyboard focus stops it
C14 autoplay playing reduced motion / hidden document prefers-reduced-motion and document.visibilityState="hidden" pause rotation unless respectReducedMotion=false reduced motion and hidden documents pause rotation
C15 controlled playing toggle / single slide emits update:playing while the controlled intent wins; one slide never rotates and disables the toggle controlled playing and single-slide carousels keep rotation stopped
C16 measured visibility intersection changes slides under half visible become inert (never the active slide) and expose data-in-view slides measured out of view become inert while the active slide stays reachable
C17 controls click with preventDefault() Previous, Next, indicators, and the autoplay toggle leave state unchanged controls honor preventDefault from click listeners
C18 exposed instance read / imperative calls exposes state and scrollTo, scrollNext, scrollPrev, play, stop, each reporting whether state changed exposes typed state and imperative navigation and rotation controls
C19 missing provider setup compound parts fail closed with the shared context diagnostic compound parts require a matching root provider
C20 geometry pure helpers index clamping/wrapping, ltr/rtl/vertical offsets, nearest-slide selection, scroll edges, and drag paging are deterministic carousel-geometry.test.ts
C21 SSR isolated requests markup is byte-identical, reflects defaultValue and autoplay, and never renders inert renders byte-identical carousel markup across isolated SSR requests
C22 SSR / hydration hydrate server markup hydrates without warnings or node replacement hydrates carousel markup without warnings or node replacement
C23 types compile states, reasons, slot state, and exposes are closed and read-only carousel.types.test-d.ts
C24 messages render role descriptions and slide/indicator names come from the typed messages prop; omitted entries keep the English WAI-ARIA wording messages localize role descriptions and slide and indicator names

Timers and listeners are client-only: they start in onMounted and stop on unmount, so server rendering never schedules rotation.