SnapCarousel Component

SnapCarousel is a controlled carousel with discrete slides, navigation arrows, and dot indicators. It supports keyboard navigation, touch/swipe gestures, and provides an imperative API for programmatic control.

Usage

Basic Carousel

A simple carousel with arrow navigation and dot indicators:

Slide 1
<SnapCarousel>
  <div>Slide 1</div>
  <div>Slide 2</div>
  <div>Slide 3</div>
  <div>Slide 4</div>
</SnapCarousel>

Controlled Mode

Control the current slide index externally with index and onIndexChange:

Controlled Slide 1

Current index: 0

const [index, setIndex] = createSignal(0);

<SnapCarousel index={index()} onIndexChange={setIndex}>
  <div>Controlled Slide 1</div>
  <div>Controlled Slide 2</div>
  <div>Controlled Slide 3</div>
</SnapCarousel>

<Button onClick={() => setIndex(0)} label="Go to first" />
<Button onClick={() => setIndex(2)} label="Go to last" />

Without Dots

Hide the dot indicators with showDots={false}:

Slide A
<SnapCarousel showDots={false}>
  <div>Slide A</div>
  <div>Slide B</div>
  <div>Slide C</div>
</SnapCarousel>

Imperative API

Use a ref to access methods for programmatic navigation:

Item 1
let carouselRef: SnapCarouselRef | undefined;

<SnapCarousel ref={(ref) => (carouselRef = ref)}>
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</SnapCarousel>

<Button onClick={() => carouselRef?.prev()} label="Previous" />
<Button onClick={() => carouselRef?.next()} label="Next" />
<Button onClick={() => carouselRef?.goToSlide(2)} label="Go to slide 3" />

Props

NameTypeDefaultDescription
childrenJSXElementrequired

Slide items to display

indexnumber0

Current active slide index (controlled mode)

onIndexChange(index: number) => voidundefined

Callback when slide changes

showMultiplebooleanfalse

Whether to show multiple items at once (visibility controlled by item styles)

showDotsbooleantrue

Whether to show dot indicators below the carousel

prevIconstring"chevron-left"

Icon name for the previous button

nextIconstring"chevron-right"

Icon name for the next button

stylesStyleXStylesundefined

Additional StyleX styles for the container

arrowStylesStyleXStylesundefined

Additional StyleX styles for arrow buttons

dotStylesStyleXStylesundefined

Additional StyleX styles for dot indicators

refSnapCarouselRef | ((ref: SnapCarouselRef) => void)undefined

Ref to access imperative API methods

Imperative API (SnapCarouselRef)

Access these methods via ref to control the carousel programmatically:

MethodTypeDescription
goToSlide(index: number) => void

Navigate to a specific slide by index

next() => void

Navigate to the next slide

prev() => void

Navigate to the previous slide

Behavior

Navigation via left/right arrow buttons (using Reef Button components)

Arrows are disabled at the ends (no wrap-around behavior)

Arrows are disabled when there are 0 or 1 children

Dot indicators below carousel allow direct navigation

Keyboard navigation with left/right arrow keys when focused

Touch/swipe gesture support on touch devices

Smooth CSS transitions when navigating (respects prefers-reduced-motion)

Scrolls by 1 item at a time

Theming

The SnapCarousel uses these theme variables for customization:

carouselGap - Gap between slides and UI elements

carouselDotSize - Size of dot indicators

carouselDotActiveColor - Color of the active dot

carouselDotInactiveColor - Color of inactive dots

carouselSnapAnimationTiming - Transition timing for slide changes

Accessibility

Uses role="region" with aria-roledescription="carousel"

Each slide has aria-roledescription="slide"

aria-live="polite" announces slide changes to screen readers

Dots use role="tablist" and role="tab" semantics

Keyboard navigable with arrow keys

Focus-visible outline on interactive elements

Respects prefers-reduced-motion preference

Edge Cases

ScenarioBehavior
0 childrenRenders nothing
1 childShows item, arrows disabled, no dots
index out of boundsClamped to valid range (0 to children.length - 1)