motion-slider
Gesture-driven horizontal carousel with spring snap, velocity-based flicking, and rubber-band edges. Works with any child content.
Preview
Import
import 'motion-components/motion-slider' // just this one
import 'motion-components' // or the whole libraryUsage
<motion-slider gap="24">
<div>Slide one</div>
<div>Slide two</div>
<div>Slide three</div>
</motion-slider>How it works
Each direct child becomes a slide, sized to fill the slider width. Pointer events are tracked across the window so drag doesn't break when the cursor leaves the element. On release, velocity is sampled over the last 6 pointer events: a fast flick snaps to the adjacent slide; a slow drag snaps to the nearest.
The spring uses the captured velocity as its initial condition, so the snap animation feels like a physical continuation of the gesture rather than a teleport.
Properties
| Attribute | Property | Type | Default | Description |
|---|---|---|---|---|
| | | number | 24 | Gap between slides in px |
| | | boolean | true | Show prev/next arrow buttons. Set |
CSS custom properties
| Property | Type | Default | Description |
|---|---|---|---|
| | color | #2563eb | Color of the keyboard focus ring on the arrows |
Methods
| Method | Description |
|---|---|
| | Animates to the slide at index. The optional initialVelocity is in px/s. Called before the slider is built, it sets the starting slide instead. The index is clamped to the slide range. |
| | Moves to the next slide. Does nothing on the last one. |
| | Moves to the previous slide. Does nothing on the first one. |
| | Read-only. Index of the active slide. |
Events
| Event | Detail | Description |
|---|---|---|
| | | Fired when the active slide changes. Bubbles and is composed. |
Other components also fire a bubbling motion-change. A listener on a parent element should check event.target.
import type { MotionSlider } from 'motion-components'
const slider = document.querySelector<MotionSlider>('motion-slider')!
slider.goTo(2)
document.querySelector('#prev')!.addEventListener('click', () => slider.prev())
document.querySelector('#next')!.addEventListener('click', () => slider.next())
document.addEventListener('motion-change', (event) => {
if (event.target !== slider) return
console.log('slide', slider.index)
})Keyboard
Focus the slider and use ArrowLeft / ArrowRight to navigate.
Accessibility
When prefers-reduced-motion is set, transitions are instant with no animation.