Motion UIComponentsComponent

Carousel controls

Prev and next buttons with animated position dots for any paged carousel.

npx shadcn@latest add @motion/carousel-controls

API reference

Components

<ArrowIcon />

The inline chevron used by StepButton. A single right-pointing arrow path, flipped with scaleX(-1) for the previous direction, drawn in currentColor (inlined, no icon dependency). Purely decorative - aria-hidden; the button that wraps it carries the accessible label.

direction

ArrowDirection

Which way the chevron points. "prev" mirrors it horizontally.

className?

string

Merged onto the <svg> element.

<StepButton />

A size-10 square bordered icon button with the theme's "snap" tap press, a hover border/text-colour transition on the shared --motion-ui-* snap timing, and the shared focus ring. Renders the built-in chevron unless you pass your own children. Purely presentational - wire it to your paging through onClick.

direction

ArrowDirection

Which control this is; drives the default chevron direction.

onClick

() => void

Fired on click - advance your carousel one step.

label

string

Accessible label for the icon-only button (e.g. "Previous slide").

children?

ReactNode

Override the icon. Defaults to the built-in ArrowIcon for direction.

disabled?

boolean

Disable the button (e.g. at the ends of a non-looping carousel).

className?

string

Merged onto the button element.

<PositionDots />

The position indicator: one mark per slide, the active one animated on the theme's timing. Compositor-only throughout (scaleX/scale/opacity and a background-colour cross-fade). Decorative by default (aria-hidden); pass onSelect to make it a real, keyboard-reachable tablist.

index

number

Index of the active slide (0-based).

total

number

Total number of slides - the dot count.

variant?

PositionDotsVariant = "bar"

The active-dot visual + motion style. Defaults to "bar".

onSelect?

(index: number) => void

When provided, each dot becomes a selectable role="tab" button inside a role="tablist", and clicking dot i calls onSelect(i). Omit for a decorative (aria-hidden) indicator whose position is announced elsewhere (e.g. the section's own aria-live region).

label?

string = "Choose a slide"

aria-label for the tablist, used only when onSelect makes the dots selectable. Defaults to "Choose a slide".

className?

string

Merged onto the track element.

<CarouselControls />

The assembled control strip: a previous StepButton, a PositionDots indicator and a next StepButton, with an optional screen-reader announcer below. Fully controlled - drive it from your own carousel state through the { index, total, onPrev, onNext } contract (bridge a motion-plus useCarousel() into the same props when the carousel owns the state).

index

number

Index of the active slide (0-based).

total

number

Total number of slides.

onPrev

() => void

Step to the previous slide.

onNext

() => void

Step to the next slide.

onSelect?

(index: number) => void

When provided, the dots become a selectable tablist and clicking dot i calls onSelect(i). Omit for a decorative indicator.

dots?

PositionDotsVariant = "bar"

The dot indicator's style, forwarded to PositionDots. Defaults to "bar".

prevLabel?

string = "Previous slide"

Accessible label for the previous button. Defaults to "Previous slide".

nextLabel?

string = "Next slide"

Accessible label for the next button. Defaults to "Next slide".

dotsLabel?

string = "Choose a slide"

aria-label for the dots tablist when onSelect is set. Defaults to "Choose a slide".

announcement?

string

Text announced in an aria-live="polite" sr-only region whenever it changes (e.g. "Slide 2 of 6: ..."). Omit if the consumer already announces carousel position elsewhere, to avoid a double announcement.

className?

string

Merged onto the control-strip root.