Swipeable media slides with dots, thumbnails, and optional autoplay
Tags: component media data-display
MediaCarousel shows one media item at a time in a horizontally scrolling track. It is built on native CSS scroll-snap, so touch swiping, momentum, and trackpad scrolling all come from the browser rather than a gesture library.
Import
<script>
import { MediaCarousel } from '@classic-homes/theme-svelte';
</script>Basic Usage
<MediaCarousel items={photos} label="Project gallery" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
items |
MediaItem[] |
required | Slides to display |
label |
string |
'Media carousel' |
Accessible name for the carousel |
index |
number |
0 |
Current slide index (bindable) |
ratio |
'square' | 'video' | 'photo' | 'portrait' | 'wide' | number |
'video' |
Aspect ratio of each slide |
loop |
boolean |
false |
Wrap from the last slide back to the first |
showDots |
boolean |
true |
Show dot indicators below the track |
showThumbnails |
boolean |
false |
Show a thumbnail strip instead of the dots |
showCaption |
boolean |
true |
Show the active slide's caption |
autoplay |
boolean |
false |
Advance automatically |
autoplayInterval |
number |
5000 |
Milliseconds between automatic advances |
onIndexChange |
(index: number) => void |
- | Called when the active slide changes |
class |
string |
- | Additional CSS classes |
Keyboard Navigation
With focus on the track:
| Key | Action |
|---|---|
← / → |
Previous/next slide |
Home / End |
First/last slide |
Thumbnails
<MediaCarousel items={photos} showThumbnails label="Project gallery" />Controlled Index
<script>
let index = $state(0);
</script>
<MediaCarousel items={photos} bind:index /><p>Viewing item {index + 1}</p>The index also follows manual swipes and scrollbar drags, so it stays accurate however the viewer moves.
Autoplay
Autoplay is off by default, and always ships with a visible pause control when enabled — a moving carousel that cannot be stopped fails WCAG 2.2.2. It also pauses on hover, pauses while focus is inside, and never starts at all when the viewer prefers reduced motion.
<MediaCarousel items={photos} autoplay autoplayInterval={7000} loop />Accessibility
- The carousel is a labelled region with
aria-roledescription="carousel". - Each slide is a group with
aria-roledescription="slide"and an "n of m" label. - Slide changes are announced through a polite live region.
- Previous and next buttons are labelled and disable at the ends unless
loopis set. - Dot indicators name the slide they jump to and mark the current one with
aria-current.