Carousel #
Published Updated Jun 7, 2026
Infinite-loop scrolling with snap-to-item, aligned with Material Design 3 Carousel patterns.
import { createVList, carousel } from "vlist";
const list = createVList({
container: "#app",
item: { height: 400, template: renderSlide },
items: slides,
}, [carousel()]);
list.on("carousel:change", ({ index }) => {
console.log("Active slide:", index);
});
Config #
Option
Type
Default
Description
variant
CarouselVariant | SlotConfig
"full"
Layout variant (see below), or a custom SlotConfig object
snap
boolean
true (false for "free")
Snap to nearest item on scroll idle
snapDuration
number
400
Snap animation duration in ms
peek
number | string | "auto"
"auto"
Visible peek of adjacent items (px, "20%", or "auto")
gap
number
0
Gap between items in px
initialIndex
number
0
Initial item index
type CarouselVariant = "static" | "full" | "hero" | "hero-center" | "multi" | "uncontained" | "free";
Custom variant #
Pass a SlotConfig object to define a custom slot layout:
carousel({
variant: { slots: [0.7, 0.2, 0.1], focalSlot: 0 },
});
Variants #
Variant
Description
Snap
"full"
One item fills the viewport edge-to-edge
Required
"hero"
One large item + one small peek item
Required
"hero-center"
One large centered item + two small peek items
Required
"multi"
Multiple visible items: large + medium + small
Required
"uncontained"
Single-size items scroll past the container edge
Optional
"free"
Items of various widths scroll freely, no snap
No
"static"
Items use their native size, no layout engine
No
Methods #
Method
Description
next(step?, options?)
Advance by step items (default 1). Smooth by default; pass { behavior: "auto" } for instant.
prev(step?, options?)
Go back by step items (default 1). Smooth by default; pass { behavior: "auto" } for instant.
goTo(index, options?)
Navigate to a specific item. Instant by default; pass { behavior: "smooth" } to animate. Options: { direction, behavior, duration }
getCarouselState()
Returns { index, scrollPosition }
goTo direction #
Direction
Behavior
"auto"
Shortest path (default)
"forward"
Always scroll forward, wrapping if needed
"backward"
Always scroll backward, wrapping if needed
Events #
Event
Payload
carousel:change
{ index, scrollPosition } — emitted when the focal item changes
CSS variables #
Updated per rendered element on every scroll frame:
Variable
Type
Description
--vlist-carousel-progress
0–1
Distance from focal center
--vlist-carousel-offset
integer
Signed item distance from focal
--vlist-carousel-role
string
"large", "medium", or "small"
--vlist-carousel-width
px
Dynamic item width
Use these in your CSS for scroll-driven effects:
.slide {
opacity: calc(1 - var(--vlist-carousel-progress) * 0.4);
filter: grayscale(var(--vlist-carousel-progress));
}
How it works #
The plugin creates a bounded virtual scroll window — the content is repeated across multiple cycles with items mapped via modulo. Scrolling past the last item seamlessly continues to the first.
Internally, the carousel delegates to the bounded scroll handler (RFC-012) via ctx.setBoundedWrap. When the scroll position drifts too far from the middle cycle, the handler folds the logical position back by whole laps — the user sees continuous forward or backward motion with no visual discontinuity.
Compatibility #
Plugin
Status
selection()
Compatible — logical indices, ARIA stays at real count
a11y()
Compatible
scrollbar()
Compatible (lap progress indicator)
autosize()
Compatible
scale()
Not compatible — both own virtual scroll space
groups()
Not compatible — infinite wrap doesn't map to grouped sections
Accessibility #
Tab focuses the first carousel item
Arrow keys navigate between items
Container has role="region", items labeled "item X of N"
prefers-reduced-motion disables item size transitions
RTL horizontal layout swaps arrow key directions
Notes #
list.total, click events, selection, and ARIA always report the real item count — the virtual cycles are strictly internal
Empty lists render nothing; all methods no-op
Single-item lists render one item; next/prev no-op
getScrollPosition() returns a normalized offset within one lap
Examples #
Carousel — MD3-aligned photo carousel with variant layouts and real photos
Plugin Wizard — carousel-powered plugin explorer with dots, prev/next, and orientation toggle
← Previous
AutoSize
Next →
Grid