Carousel
.carousel, .carousel-track, .carousel-slide, then .carousel-prev / .carousel-next on outline icon buttons. The track is overflow-x: auto with scroll-snap-type: x mandatory.
There is no wrapper. A few lines of scrollBy on the page
(slide width) are enough — pasting that twice is painful, so the
helper lives next to the markup.
Preview
Code
<script>
let track;
function step(dir) {
track.scrollBy({ left: dir * track.clientWidth, behavior: 'smooth' });
}
</script>
<div class="carousel">
<div class="carousel-track" bind:this={track} role="region" aria-label="Example slides">
<div class="carousel-slide">
<p>Slide 1 of 3</p>
<p>Native overflow and CSS scroll-snap.</p>
</div>
<div class="carousel-slide">
<p>Slide 2 of 3</p>
<p>Prev and next call scrollBy.</p>
</div>
<div class="carousel-slide">
<p>Slide 3 of 3</p>
<p>One full slide at a time.</p>
</div>
</div>
<button class="button button-outline button-icon carousel-prev" type="button" aria-label="Previous slide" onclick={() => step(-1)}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<button class="button button-outline button-icon carousel-next" type="button" aria-label="Next slide" onclick={() => step(1)}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</div>