Carousel
A swipeable slideshow with edge controls and indicator dots.
Basic
The .carousel region wraps a .carousel__viewport that clips a .carousel__track of .carousel__slide children, with optional prev/next .carousel__control chips, a .carousel__indicators row, and per-slide .carousel__caption overlays. The slide motion (Embla, which writes a transform on the track) ships with the JS layer. The overlay chrome reads the theme-independent overlay tokens so it stays legible over any imagery in light or dark. This basic example is a 16:9 viewport with controls on the slide edges, a dot row at the bottom (the active dot stretches to a pill), and a caption gradient on the first slide.
Without a fixed ratio
Add .carousel--no-aspect so the viewport sizes to the slide content instead of locking to 16:9 — useful for text cards of varying height.
Keyboard
The root is focusable. Once focus lands on the carousel itself (not on a slide child), these keys move the track.
- ArrowLeft: previous slide
- ArrowRight: next slide
- Home: first slide
- End: last slide
With controls
Add .carousel__control--prev and .carousel__control--next as direct children of the root. The wrapper auto-disables the chip at the end of the track unless loop is on.
With indicators
One .carousel__indicator button per slide inside .carousel__indicators. The wrapper paints the active chip via [data-state="active"] and aria-current="true".
With captions
Drop a .carousel__caption inside any .carousel__slide. It pins to the bottom edge with a gradient overlay.
Card content
Slides aren't limited to images. Add .carousel--no-aspect on the root and the viewport sizes to its tallest slide instead of locking to 16:9. The chrome tokens can be retuned to track theme surfaces so the controls and indicators read on both light and dark.
Autoplay
Pass data-stisla-carousel-autoplay="true" for a 4s tick. Autoplay pauses on hover, on focus, while dragging, and while the tab is hidden. Reduced motion turns it off entirely.
Loop
data-stisla-carousel-loop="true" wraps past the last slide back to the first. The prev / next chips stay enabled at the ends.
Events
Four events fire on the carousel root. None are cancelable; they report state after the change has already landed.
stisla:carousel:selected fires when the highlighted slide changes (drag, click, key, or autoplay). The detail object carries the new index and the previousIndex. Use it for highlight sync.
stisla:carousel:settled fires after the slide transition ends and the track is at rest at the new index. Use it for work that should wait until motion is done, like lazy-loading the visible slide.
stisla:carousel:autoplay-paused fires when autoplay pauses; the detail.reason is one of "hover", "focus", "drag", or "visibility".
stisla:carousel:autoplay-resumed fires when autoplay resumes, with the same detail.reason field.
Customization
These variables retune the carousel. Override on the root or any wrapper.
| Variable | Use |
|---|---|
--carousel-radius | Viewport corner radius |
--carousel-aspect-ratio | Viewport ratio (default 16/9; ignored under --no-aspect) |
--carousel-slide-gap | Inline gap between slides |
--carousel-control-size / -control-inset | Control chip size and edge inset |
--carousel-control-bg / -control-bg-hover / -control-color | Control chip paint |
--carousel-indicators-inset / -indicator-gap | Indicator row position and spacing |
--carousel-indicator-size / -indicator-width-active | Dot size and active pill width |
--carousel-indicator-bg / -indicator-bg-active | Dot color, resting and active |
--carousel-caption-padding-block / -caption-padding-inline | Caption padding |
--carousel-caption-bg / -caption-color | Caption gradient and text |
--carousel-transition-duration | Control and indicator timing; zeroed under reduced-motion |