Carousel
A horizontal snap carousel backed by native scroll-snap, with optional controls, dots, autoplay, loop, and peek.
Implementation previewEvery example. In one place.
Explore every named example, including states, compositions, and theme variants.
Example source
packages/design-system/src/components/layout/Carousel/Carousel.stories.tsxExport PlaygroundImplementation preview Local Storybook build 0.2.0-preview.1. Source specification status does not approve this runtime.
Stories + source JSON ↗Local specification source status: preview. Implementation preview pending sign-off.
A horizontal snap carousel backed by native scroll-snap, with optional controls, dots, autoplay, loop, and peek.
Implementation API 1 entry point · source-derived preview
Read the actual callable API and preserve its composition constraints. Each union branch is a complete alternative; props marked forbidden cannot be supplied.
import { Carousel } from '@cloakedinc/design-system';CarouselCarouselProps
packages/design-system/src/components/layout/Carousel/Carousel.tsx:79
| Prop | Type | Presence | Notes |
|---|---|---|---|
children | React.ReactNode | Required | |
gap | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined | Optional | Space between slides, in `--cds-space-*` steps.Source default: 16 |
snap | boolean | undefined | Optional | Enables native CSS scroll snap. Defaults to `true`.Source default: true |
snapType | CarouselSnapType | undefined | Optional | Snap strength. Defaults to `mandatory`; use `proximity` for looser, free-er scrolling.Source default: 'mandatory' |
snapStop | CarouselSnapStop | undefined | Optional | Hard snap stop per card. Defaults to `normal`; `always` is more magnetic — each swipe lands on the neighbor.Source default: 'normal' |
snapAlign | CarouselSnapAlign | undefined | Optional | Snap alignment for each slide. Defaults to `start`.Source default: 'start' |
slideWidth | CarouselSlideWidth | Optional | Slide width. `peek` leaves room for the configured next-card peek. Defaults to `full`.Source default: 'full' |
peek | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined | Optional | Visible next-card width when `slideWidth='peek'`, in `--cds-space-*` steps.Source default: 40 |
fullBleed | boolean | undefined | Optional | Cancels one page gutter so the strip bleeds to the screen edges while items stay aligned to the gutter.Source default: false |
inset | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined | Optional | Leading/trailing inset on the scroll strip, in `--cds-space-*` steps (snap-aware edge bleed).Source default: 0 |
dots | boolean | undefined | Optional | Shows pagination dots below the strip.Source default: false |
controls | boolean | undefined | Optional | Shows previous/next controls over the strip.Source default: false |
autoplay | boolean | undefined | Optional | Automatically advances slides, pausing while hovered, interacting or focused within. Defaults to `false`.Source default: false |
autoplayInterval | number | undefined | Optional | Autoplay interval in milliseconds. Defaults to `3000`.Source default: DEFAULT_AUTOPLAY_INTERVAL |
loop | boolean | undefined | Optional | Wraps previous/next/autoplay around both ends.Source default: false |
selectedIndex | number | undefined | Optional | Controlled selected slide index. |
defaultSelectedIndex | number | undefined | Optional | Initial selected slide index for uncontrolled usage.Source default: 0 |
onSelectedIndexChange | ((index: number) => void) | undefined | Optional | Fires on every selection change — swipe, control, dot, or autoplay — controlled or not. |
haptic | HapticFeedback | undefined | Optional | Haptic feedback for user-driven slide changes. Defaults to `true` (`selection`).Source default: true |
ariaLabel | string | undefined | Optional | Accessible label for the carousel region. |
className | string | undefined | Optional | |
style | React.CSSProperties | undefined | Optional | |
testId | string | undefined | Optional | Root selector. Children derive from it: `-strip`, `-previous`/`-next`, `-item-${index}`, and `-dot-${index}`. |
Only explicit destructured parameter initializers are extracted. Other runtime defaults remain in implementation source.
Overview
Horizontal snap carousel backed by native CSS scroll-snap. Touch scroll works with zero props;
controls, dots, autoplay, and loop are opt-in.
When to use
Reach for Carousel when content is paged horizontally, one (or one-plus-a-peek) card per
view — dashboard stat cards, an onboarding walkthrough, a news strip. The snap feel comes from
snapType (mandatory always rests on a card vs proximity for looser free-scroll) and
snapStop (always is magnetic, one card per flick, vs normal which lets momentum skip
several). Set slideWidth="peek" with peek to reveal the next card.
- Just need a plain overflowing row with no snapping? Use
HStackwithscroll. - Laying out tiles in a static grid rather than a swipeable strip? Use
Grid.
Component specification
$schema
../../../specs/component-spec.schema.jsonParts
- Id
- root
- Label
- Root
- Description
- Region wrapper carrying gap, slide width, and snap settings. Structural container.
- Required
- true
- Id
- strip
- Label
- Strip
- Description
- Scrolling flex track that holds the slides.
- Id
- item
- Label
- Item
- Description
- One snap slide sized by the slide width.
- Id
- controls
- Label
- Controls
- Description
- Optional previous/next buttons over the strip.
- Id
- dots
- Label
- Dots
- Description
- Optional pagination dots below the strip.
Allowed Design Choices
- Variants
- Carousel
- Label
- Carousel
- Description
- The single horizontal snap carousel.
- Sizes
- Snap Types
- Mandatory
- Label
- Mandatory
- Description
- Always rests on a card.
- Proximity
- Label
- Proximity
- Description
- Only snaps when a card is already close.
- Snap Stops
- Normal
- Label
- Normal
- Description
- Momentum can skip several cards.
- Always
- Label
- Always
- Description
- Each flick lands on the adjacent card.
- Snap Alignments
- Start
- Label
- Start
- Center
- Label
- Center
- End
- Label
- End
- Slide Widths
- Full
- Label
- Full
- Description
- One slide per view.
- Peek
- Label
- Peek
- Description
- Leaves room for the next card's edge. Besides full and peek, slideWidth also accepts an explicit CSS flex-basis value passed through unchanged.
Variants
- Id
- carousel
- Label
- Carousel
- Description
- Horizontal snap carousel.
- Platforms
- ios
- android
- web
Sizes
None specifiedMeasurements
- Id
- slide-gap
- Label
- Slide gap
- Kind
- example-only
- Token
- --cds-space-12
- Value
- 12
- Unit
- px
- Applies To
- strip
- Notes
- Configurable: the default slide gap is 16 (--cds-space-16) and the prop accepts any step on the spacing scale. 12 is the representative value rendered by the controls story.
- Id
- control-size
- Label
- Control button size
- Kind
- exact
- Token
- --cds-size-32
- Value
- 32
- Unit
- px
- Applies To
- controls
Layout
- Alignment
- Slides align to the chosen snap edge; controls overlay the strip and dots sit below it.
- Flow
- A scrolling flex track of snap slides with optional overlaid controls and pagination dots.
- Notes
- Use HStack scroll for a plain non-snapping overflow row.
Typography And Color
- Typography
- Label
- Inherited
- Description
- Carousel sets no type; slides own their text. Ramp noted for parity.
- Token
- --cds-type-body-size
- Colors
- Label
- Control surface
- Description
- Control buttons sit on the raised surface.
- Token
- --cds-bg-surface
- Label
- Active dot
- Description
- The active dot uses primary text color.
- Token
- --cds-text-primary
- Label
- Inactive dot
- Description
- Inactive dots use the divider color.
- Token
- --cds-divider
States
- Id
- default
- Label
- Default
- Description
- Touch-scroll snap with no controls or dots.
- Id
- controls
- Label
- Controls
- Description
- Previous/next buttons and dots enabled.
- Id
- peek
- Label
- Peek
- Description
- Slides sized to reveal the next card's edge.
- Id
- autoplay
- Label
- Autoplay
- Description
- Auto-advancing; hover, pointer interaction and focus within the carousel pause it.
Behavior
- Label
- Snap feel
- Description
- snapType sets snap strength and snapStop sets per-card stopping.
- Label
- Selection
- Description
- Scrolling updates the selected index; controls and dots also drive it.
Accessibility
- Label
- Region
- Description
- The carousel is a role=region named by ariaLabel.
- Label
- Control labels
- Description
- Previous, next, and dot controls carry accessible labels.
- Label
- Keyboard reachability
- Description
- All slide content stays exposed to assistive technology. Tab reaches interactive descendants and native scrolling brings focused controls into view. Autoplay pauses while focus remains inside.
Content Adaptation
- Label
- Peek gutter
- Description
- slideWidth=peek with peek reveals the next card to signal more content.
- Label
- Custom slide width
- Description
- Beyond full and peek, slideWidth accepts an explicit CSS flex-basis value passed through unchanged.
- Label
- Single slide
- Description
- Controls and dots hide themselves when there is nothing to page to.
Motion Haptics
- Motion
- Label
- Snap scroll
- Description
- Native scroll-snap drives resting positions; control taps scroll smoothly.
- Haptics
- Label
- Selection haptic
- Description
- User-driven slide changes request the selection haptic.