Carousel
A scroll-snap track of slides with prev/next controls, dots, keyboard, and opt-in autoplay.
Live demo
Carousel lays its slotted children out as a horizontal scroll-snap track: each child is a slide, and the browser's own scrolling does the paging, so the track is swipeable and keyboard-scrollable with no JavaScript at all. When the runtime is present it grows a control bar, prev and next buttons (drawn with the chevron icons), a row of pagination dots that track and drive the active slide, and arrow-key and Home/End navigation, all wired over the same native scroll.
An opt-in autoplay advances the track on an interval, pausing on hover and focus and standing still entirely under prefers-reduced-motion; loop wraps the ends seamlessly, scrolling into an inert clone of the far slide and then silently snapping to the real one so the wrap never rewinds. The transition prop swaps the paging model: slide keeps the scroll-snap track, while fade, scale, and flip stack the slides and cross-fade the active one, so a testimonial or hero rotator can dissolve rather than slide. It is content-agnostic: the slides can be Images, Cards, or any markup, and it exposes itself as a labelled carousel region with each slide named for assistive tech.
Everything the carousel draws — the viewport, the track, the control bar, the arrows, the dots, and the play toggle — is its fragment's markup, so a mod can restyle or restructure the chrome (swap the chevrons for arrows, turn the dots into thumbnails, move the bar) without touching the scroll math, the keyboard, or the loop. The slides themselves are never re-authored: the fill's track is filled with the consumer's own nodes, so framework content stays live.
When to use
How this component composes with the rest of the set.
Props
10 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
interval. Pauses on hover and focus, and never runs under reduced-motion. | ||||
true renders them in a bar below the track; "overlay" floats them on the slide edges (arrows at the left/right, dots and the play toggle over the bottom) for an in-image gallery; "false" hides them and relies on swipe, dots, and keys. The overlay layer is click-through except for the controls, so a swipe or a link inside a slide still works. | ||||
dots="false" to hide them. | ||||
pause-on-hover="false" when the rotation is the point and should keep running under the pointer: a decorative marquee, an ambient gallery, or a preview revealed inside an Image's hover slot (which only shows while hovered, so a hover-pause would freeze it on its first slide). The explicit play/pause toggle and prefers-reduced-motion still stop it, so the content stays pausable. | ||||
slide (the default) pages a scroll-snap track sideways; fade, scale, and flip instead stack the slides and cross-fade the active one (scale adds a subtle zoom, flip a card turn). The stacked modes have no swipe track, so they lean on the controls, dots, and keys. | ||||
slide carousel advances. right (the default) and left page a horizontal track; up and down a vertical one (give it a height with --carousel-height, default 18rem). left and up reverse the sense. Moot for the stacked transitions. | ||||
Anatomy
The named parts that make up the component. A ::part() handle is reachable from your own stylesheet; the class beside it is the component's internal selector, which a shadow boundary keeps to itself.
viewport
The clipping frame around the track. It sets the vertical carousel's height from --carousel-height.
track
The scroll-snap container that holds and pages the slides. The consumer's slides are relocated into it, so they stay the same live nodes they were authored as.
controls
The bar the arrows, dots, and play toggle sit in, below the track — or floated over the slides under controls="overlay".
nav
The prev/next buttons, each drawn with the chevron pointing the way the track advances.
play
The play/pause toggle an autoplay carousel grows, so the motion can always be stopped outright.
dots
The pagination dots; the active one takes the accent. When the theme's --selection-cue resolves to marker, the active dot also elongates into a pill so the current slide reads by shape, not color alone.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent--bg-1--bg-2--bg-3--border-thick--border-thin--duration-fast--duration-slow--ease-emphasized--ease-standard--elevation-2--fg-1--fg-2--fg-3--line-2--radius-full--ring--selection-cue--space-2--space-3--space-6--surface-overlay--surface-overlay-borderSlots
The slides. Each direct child becomes one slide in the track (an Image, a Card, or any markup).
Accessibility
Code
Image gallery
A few slides in a scroll-snap track with prev/next controls and dots.
<xtyle-carousel label="Product photos">
<img src="/a.jpg" alt="Front" />
<img src="/b.jpg" alt="Side" />
<img src="/c.jpg" alt="Back" />
</xtyle-carousel><script lang="ts">
import { Carousel } from "@xtyle/svelte";
</script>
<Carousel label="Product photos">
<img src="/a.jpg" alt="Front" />
<img src="/b.jpg" alt="Side" />
</Carousel>---
import Carousel from "@xtyle/astro/Carousel.astro";
import Image from "@xtyle/astro/Image.astro";
---
<Carousel label="Gallery">
<Image src="/a.jpg" alt="First" ratio="16/9" />
<Image src="/b.jpg" alt="Second" ratio="16/9" />
</Carousel>Autoplay and loop
An auto-advancing, looping track that pauses on hover or focus.
<xtyle-carousel label="Highlights" autoplay interval="4000" loop>
<div>Slide one</div>
<div>Slide two</div>
<div>Slide three</div>
</xtyle-carousel><script lang="ts">
import { Carousel } from "@xtyle/svelte";
</script>
<Carousel label="Highlights" autoplay interval={4000} loop>
<div>Slide one</div>
<div>Slide two</div>
</Carousel>---
import Carousel from "@xtyle/astro/Carousel.astro";
---
<Carousel label="Highlights" autoplay interval={4000} loop>
<div>Slide one</div>
<div>Slide two</div>
</Carousel>Fade transition
A stacked cross-fade instead of a sliding track, for a testimonial or hero rotator.
<xtyle-carousel label="Featured" transition="fade" autoplay loop>
<div>First</div>
<div>Second</div>
<div>Third</div>
</xtyle-carousel><Carousel label="Featured" transition="fade" autoplay loop>
<div>First</div>
<div>Second</div>
<div>Third</div>
</Carousel><Carousel label="Featured" transition="fade" autoplay loop>
<div>First</div>
<div>Second</div>
<div>Third</div>
</Carousel>