Navigation

Carousel

Rotating content viewport with previous/next controls, picker dots, and optional autoplay.

import { Carousel } from '@lostgradient/cinder/carousel';
navigationcarouselmedia
01

Overview

Composable slide rotator with controls, indicators, keyboard support, and optional autoplay.

Usage

svelte
<script lang="ts">
  import { Carousel } from '@lostgradient/cinder/carousel';

  const slides = [
    { id: 'one', label: 'Welcome', title: 'Welcome', description: 'Start here' },
    { id: 'two', label: 'Features', title: 'Features', description: 'What is included' },
  ];
</script>

<Carousel {slides} autoplay />

loop defaults to false. Previous/Next clamp and disable at the ends instead of wrapping. Set loop to wrap past the first/last slide. Wrapping is seamless only for the first cycle through the deck — slides is rendered in a rotated physical order (via CSS order) starting from the initial activeIndex, so the first wrap navigation lines up with an adjacent physical slide. Repeated wraps after that reuse the same rotated order and are not guaranteed to be adjacent, so they animate as a longer traversal rather than a single seamless step.

slidesPerView and loop are mutually exclusive. Setting slidesPerView above 1 while loop is also set logs a dev warning and ignores loop — wrapping a multi-slide range across the physical-order rotation boundary would leave a partial-width gap. slidesPerView above 1 also widens the active range: more than one slide is non-inert at once, and the live region announces "Slides N–M of Total" instead of a single labelled slide. See carousel.a11y.md for the full review.

svelte
<!-- Peek layout: 1.2 slides visible, hinting at the next one -->
<Carousel {slides} slidesPerView={1.2} gap="1rem" />

Mouse users get click-and-drag scrolling, with momentum, automatically. On a fine pointer ((hover: hover) and (pointer: fine)) with prefers-reduced-motion off, clicking and dragging the track scrolls it with the same physics a released swipe would have, snapping to the nearest slide on release. There is no prop to opt out per-instance today — it degrades automatically under reduced motion, and never engages for touch or pen (they already pan the native scroller directly). See carousel.a11y.md for the full review.

Live preview
02

When to use

Use when
  • Presenting a finite set of visual highlights with sequential browsing controls.
  • Cycling between promotional or tutorial panels inside a single region.
Avoid when
  • Content should remain simultaneously visible and scannable. Use Grid instead
  • You only need one static hero panel with no sequence controls.
03

Examples

Basic carousel

Prev/next navigation with indicator dots and autoplay support.

Multi-slide peek

slidesPerView shows more than one slide at once; a fractional value peeks the next slide.

04

Props

Props for carousel
NameTypeDefaultDescription
slides required TSlide[] Ordered list of slides.
activeIndex bindable number 0 Zero-based active index (bindable).
autoplay boolean false Enables interval-based auto-advance.
autoplayInterval number 5000 Milliseconds between auto-advance ticks.
loop boolean false Wraps navigation past the first/last slide back around. Default false: Previous/Next clamp and disable at the ends instead of wrapping.
label text 'Carousel' Accessible name for the carousel region.
description text Optional accessible description linked to the region.
controlLabels { previous?: string; next?: string; picker?: string; pause?: string; play?: string; } Override labels for controls and picker.
indicators 'dots' | 'counter' | 'none' How the slide picker is rendered. 'dots' below indicatorLimit degrades automatically to 'counter' above it when left unset.
indicatorLimit number 8 Slide count above which the auto-resolved picker switches to a counter. Default 8.
slidesPerView number 1 How many slides are visible at once. A fraction (e.g. 1.2) peeks the next slide. 'auto' lets each slide size itself via its own CSS. Default 1. Not supported together with looploop is ignored (with a dev warning) while this is set above 1.
gap text Gap between slides, as a CSS length (e.g. '1rem'). Only applied when slidesPerView is not 1.
align 'start' | 'center' 'start' Snap alignment of the active slide(s) within the viewport. Default 'start'.
onSlideChange (index: number, slide: TSlide) => void Called after the active slide changes as a result of the carousel's own navigation (never for a parent-driven activeIndex update).
slide snippet Renders inside each slide's <article>, replacing the built-in image/title/description/link body. slides remains the identity and accessible-labeling source of truth — this only replaces slide content.
onkeydown KeyboardEventHandler<T>undefinednull
onmouseenter MouseEventHandler<T> | undefined | null
onmouseleave MouseEventHandler<T> | undefined | null
onfocusin FocusEventHandler<T> | undefined | null
onfocusout FocusEventHandler<T> | undefined | null
05

Accessibility

ArrowLeft/ ArrowRight/ Home/ End
Moves between slides.
Auto-advance pauses on hover and focus, and is disabled under reduced motion.