Carousel
Containers

Carousel

Scroll-snap track with arrow buttons, position dots, and optional autoplay. Swipe, wheel, arrows, and keyboard all move the same scroll position.

Component behavior

Carousel uses native scrolling and CSS scroll snapping. Pointer gestures, wheel input, and navigation buttons update the same scroll position. The active index is derived from that position.

Use cases
  • A short browsable collection, such as release notes, onboarding steps, screenshots.
  • Horizontal card collections with slide navigation.
Alternatives

ScrollArea: the region needs scrolling without slide controls, indexing, or autoplay.

Tabs: users select views by name.

Stepper: a task has ordered steps and completion state.

Props

Carousel extends HTMLAttributes<HTMLDivElement> (minus onChange).

CarouselProps props
PropTypeDefaultDescription
childrenReactNode—CarouselSlide children.
perViewnumber1Number of visible slides. Fractional values display part of the next slide.
gapkeyof SpacingScale | string | number3Space between slides, from the spacing scale.
indexnumber—Controlled active slide index. Use with onIndexChange.
defaultIndexnumber0Starting slide when uncontrolled.
onIndexChange(index: number) => void—Fires when the active slide changes, including from a manual scroll.
loopboolean—Wraps past the ends instead of stopping.
autoPlaynumber—Advance every N milliseconds. Pauses on hover, focus and off-screen.
arrowsbooleantruePrevious / next buttons over the track.
dotsbooleantruePosition dots under the track.
labelstring"Carousel"Names the region for assistive tech.

Keyboard

The track is a tab stop. From it, ← and → step by one slide, Home and End jump to the ends, and the arrows and dots are ordinary buttons with their own labels. Each slide is a group labelled "n of m", so a screen reader announces where it is in the set.

Examples

One at a time

Carousel

Several at a time, with a peek

A fractional perView leaves part of the next slide visible, which signals that the strip continues. This is the same job the edge fade does in a ScrollArea.

Carousel (perView 2.25)

Looping

Carousel (loop)
ImportTSX
import { Carousel, CarouselSlide } from "@solarius/onset";

<Carousel perView={1} label="Onboarding" onIndexChange={setStep}>
  <CarouselSlide><Step one /></CarouselSlide>
  <CarouselSlide><Step two /></CarouselSlide>
</Carousel>

// A card strip that peeks at the next item:
<Carousel perView={3.2} gap="2" arrows dots={false}>
  {items.map((i) => <CarouselSlide key={i.id}><Card /></CarouselSlide>)}
</Carousel>