Skip to main content
xriptxr

Carousel

Info:Media
23

A scroll-snap track of slides with prev/next controls, dots, keyboard, and opt-in autoplay.

slideshow gallery slides swiper scroll snap slider

Live demo

live · @xtyle/astro

Carousel

Image gallery

With controls="overlay" the prev/next arrows ride the slide edges and the dots float over the bottom, for an in-image gallery. The overlay is click-through except for the controls.

Hover previews in a carousel

Each slide is an Image carrying its own preview, and each one is a different kind: a hover-src video, a nested carousel, and a moving image. Hovering (or focusing) a slide reveals its preview and pauses the outer carousel's autoplay in the same gesture; leaving resets both.

Autoplay and loop

Advances every 4s and loops seamlessly at the ends (no rewind), pausing when you hover or focus it.

Fade, scale, and flip transitions

transition stacks the slides and cross-fades the active one instead of paging a track: fade dissolves, scale adds a zoom, flip turns the card. Each auto-advances so you can watch the motion.

fade

scale

flip

Direction: vertical and reversed

direction sets the axis and sense: up / down page a vertical track (give it a height with --carousel-height), and left advances a horizontal track in reverse.

down (vertical)

left (reversed)

Content slides

Bare track

With both controls={false} and dots={false} the carousel draws no chrome at all: the control bar drops out entirely and the slides are paged by swipe, the arrow keys, and Home/End. Everything the other demos show above it — the arrows, the dots rail, the play toggle, the track itself — is the component's fragment, so a mod can restyle or restructure any of it without touching the scrolling.

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.

Put Images in the track for a photo gallery; pair each with a ratio so the slides stay a consistent height.
Slot Cards for a featured-content rail, or any markup for a testimonial or onboarding sequence.
Set autoplay with loop for an unattended hero rotation; it pauses the moment a user hovers or focuses it.
Set controls="false" on a touch-first surface to lean on swipe and dots alone.
A vertical direction (up / down) suits uniform, media-shaped slides: it pins each slide to --carousel-height and clips the overflow, so give it a height that fits the content and reach for it over long text cards.

Props

10 props, straight from the manifest.

PropTypeDefaultBindingsDescription
label string
html svelte astro
The accessible name for the carousel region. Always set it so assistive tech can announce the carousel.
autoplay boolean false
html svelte astro
Auto-advances the track on the `interval`. Pauses on hover and focus, and never runs under reduced-motion.
interval number 5000
html svelte astro
The autoplay dwell per slide, in milliseconds.
loop boolean false
html svelte astro
Wraps seamlessly past the last slide to the first (and back): the track scrolls forward into an inert clone of the far slide, then silently snaps to the real one, so the wrap reads as continuous motion instead of a rewind. The prev/next buttons stay enabled at the ends.
controls boolean | "overlay"
true false overlay
true
html svelte astro
Where the prev/next buttons sit: `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 boolean true
html svelte astro
Shows the pagination dots. Set `dots="false"` to hide them.
pause-on-hover boolean true
html svelte astro
Whether hovering or focusing the carousel pauses autoplay. Set `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.
transition CarouselTransition
slide fade scale flip
slide
html svelte astro
How slides change. `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.
direction CarouselDirection
right left up down
right
html svelte astro
Which way a `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.
static boolean false
astro
Astro only: keep the server-rendered frame and the slides but never load the runtime to hydrate them — the slides render in the fill's track as a plain strip. The arrows, dots, autoplay, seam-clone looping, and keyboard are what hydration adds. The Svelte and raw-element paths always upgrade, so they carry no equivalent.

Anatomy

The named parts that make up the component, with their selectors.

viewport

.xtyle-carousel__viewport

The clipping frame around the track. It sets the vertical carousel's height from --carousel-height.

track

.xtyle-carousel__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.

--space-3 --ring --border-thick

controls

.xtyle-carousel__controls

The bar the arrows, dots, and play toggle sit in, below the track — or floated over the slides under controls="overlay".

--space-3 --surface-overlay --surface-overlay-border

nav

.xtyle-carousel__nav

The prev/next buttons, each drawn with the chevron pointing the way the track advances.

--bg-1 --bg-2 --fg-1 --line-2 --radius-full --elevation-2

play

.xtyle-carousel__nav--play

The play/pause toggle an autoplay carousel grows, so the motion can always be stopped outright.

--bg-1 --fg-1 --line-2 --radius-full

dots

.xtyle-carousel__dot

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.

--bg-3 --fg-2 --fg-3 --accent --selection-cue --space-2 --duration-fast --ease-standard

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 23/23 consumed tokens produced default register: 305 tokens

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-border

Slots

default
html svelte astro

The slides. Each direct child becomes one slide in the track (an Image, a Card, or any markup).

Accessibility

The carousel is a labelled region with aria-roledescription="carousel", and each slide is a labelled group announced as N of M.
The track is focusable and scrolls with the arrow keys and Home/End; the prev/next buttons and dots are labelled controls.
Autoplay pauses on hover and focus, and stops entirely under prefers-reduced-motion, so motion never runs against a user's stated preference.
An autoplay carousel grows a persistent play/pause toggle in the control bar (WCAG 2.2.2): the user can stop the motion outright, and a deliberate pause survives a pointer leaving and re-entering, unlike the transient hover pause.
The active slide is announced through a polite live region (Slide N of M), so a screen-reader user hears each change even though scrolling, or a stacked cross-fade, never moves focus.
With no JavaScript the slides remain visible and the track stays natively scrollable, so no content is trapped behind the enhancement.
The current slide carries a non-color channel on demand: when the theme sets --selection-cue: marker, the active dot elongates into a pill alongside the accent color, so which slide is current never rests on color alone (WCAG 1.4.1). High-contrast emits marker by default, and any algorithm can opt in via the cues knob.

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>