Horizontal card slider for the modern web. Requires minimum JavaScript. Demo
<noscript>
.[^1]: The buttons are shown only when hovered with @media (pointer: fine)
such as a mouse cursor.
[^2]: For accessibility, wrap the card component with tabbable elements such as <a>
or <button>
.
Tested on the latest evergreen browsers.
Chrome | Safari | Firefox | Safari (iOS) | Samsung Internet | |
---|---|---|---|---|---|
CSS [Scroll Snap] | 69 | 11 | 68 | 11 | 10.1 |
CSS [Scroll-behavior] | 61 | 15.4 | 36 | 15.4 | 8.2 |
npm create svelte@latest
npm i swipe-scroller -D
Following code is based on SvelteKit v1.
<!-- src/routes/+layout.svelte -->
<script>
import 'swipe-scroller/style';
</script>
<div class="container-outer" style="position: fixed; inset: 0;" />
<div style="position: relative; overflow-x: hidden;">
<slot />
</div>
<!-- src/routes/+page.svelte -->
<script>
import Scroller from 'swipe-scroller/Scroller.svelte';
</script>
<div class="container-inner">
<h1>Swipe Scroller</h1>
</div>
<Scroller>
{#each { length: 5 } as _, index}
<a href="#{index}" class="card">
<img src="https://picsum.photos/572?random={index}" draggable="false" alt="" />
<div>Card No. {index + 1}</div>
</a>
{/each}
</Scroller>
<style>
.card {
text-decoration: none;
color: white;
background-color: gray;
width: 80%;
min-width: 224px;
max-width: 296px;
overflow: hidden;
}
.card > img {
display: block;
aspect-ratio: 1;
width: 100%;
}
.card > div {
padding: 1rem;
text-align: center;
}
</style>
Reference how it works for an in-depth explanation.
The following DOM events are forwarded to the component.
<!-- Provide custom callbacks if needed. -->
<Scroller on:scroll on:scrollend />
// Optional Component Props
/** Width and height of the clickable control buttons. */
export let buttonWidth = '2.5rem';
/** Horizontal gap between the provided card components. */
export let cardGap = '1.25rem';
/** Hang control buttons on the outer container border. */
export let hangButtons = true;
/** Invert the scroll direction of the control buttons. */
export let invertButtons = false;
<!-- Optional Named Slots -->
<slot name="noscript" />
<slot name="button-prev" />
<slot name="button-next" />