A scroll-snap carousel that wraps your
.wf-carousel-item
children in a scrollable track. Supports navigation arrows, pagination dots, autoplay, mouse drag, multi-slide-per-page, and vertical orientation — all through data attributes. The programmatic API is available on
el._wfCarousel
after the component initializes.
Basic Carousel
Minimal Setup
Add
data-wf-carousel
to a
.wf-carousel
wrapper containing
.wf-carousel-item
children. Mouse drag and touch scroll are enabled by default — no further options are required.
data-wf-navigation
adds prev/next arrow buttons.
data-wf-pagination
adds clickable dot indicators below the track.
data-wf-loop
wraps from the last slide back to the first. Without a loop, arrow buttons disable automatically at the boundaries.
data-wf-slides-per-page
sets how many slides are visible simultaneously — slide width is calculated automatically. Use
data-wf-slides-per-page-sm
to override on narrow viewports (< 42rem).
data-wf-slides-per-move
controls how many slides the prev/next buttons advance per click.
data-wf-autoplay
starts auto-advancing after init.
data-wf-autoplay-interval
sets the delay in milliseconds (default 3000, minimum 500). Autoplay pauses automatically on hover and focus and resumes when the pointer leaves. Use
data-wf-loop
alongside autoplay to prevent stopping at the last slide.
Set
data-wf-orientation="vertical"
to switch to a column flex layout. Slide height is controlled by
--wf-carousel-slide-height
(default: 300px). Navigation buttons move to the top and bottom edges; pagination dots stack vertically at the inline-end edge.
Add
data-wf-gallery-sync="#selector"
pointing to an external element that contains thumb items. Each thumb needs a
data-thumb="index"
attribute (0-based) matching the corresponding slide. The carousel adds
.is-active
to the matching thumb on every slide change, and clicking a thumb jumps to that slide.
Required. Marks the wrapper for auto-init on DOMContentLoaded.
data-wf-navigation
off
Show previous / next arrow buttons.
data-wf-pagination
off
Show clickable dot indicators below (or beside, in vertical mode) the track.
data-wf-loop
off
Wrap from the last slide back to the first, and vice versa. Keeps nav buttons always enabled.
data-wf-autoplay
off
Automatically advance slides. Pauses on hover and focus; resumes on leave.
data-wf-autoplay-interval="ms"
3000
Milliseconds between auto-advances. Minimum enforced: 500.
data-wf-mouse-dragging
on
Allow click-and-drag scrolling on desktop. Set to
"false"
to disable.
data-wf-slides-per-page="n"
1
Number of slides visible simultaneously. Slide width is computed automatically.
data-wf-slides-per-page-sm="n"
1
Visible slides on narrow viewports (< 42rem). Overrides
data-wf-slides-per-page
at that breakpoint.
data-wf-slides-per-move="n"
1
Number of slides to advance per next / previous call.
data-wf-orientation="vertical"
horizontal
Switches track to column flex, moves buttons to top / bottom, and uses
--wf-carousel-slide-height
instead of aspect-ratio.
data-wf-disabled
off
Disable all interaction. Dims the carousel and blocks pointer events.
data-wf-gallery-sync="#selector"
—
CSS selector for an external element containing thumb items. Each thumb needs
data-thumb="index"
(0-based). The carousel adds
.is-active
to the matching thumb and clicking any thumb jumps to that slide.
CSS Custom Properties
Property
Default
Description
--wf-carousel-aspect-ratio
16 / 9
Aspect ratio of each
.wf-carousel-item
. Set to
unset
if slides have a fixed height.
--wf-carousel-gap
1rem
Gap between slides in the track.
--wf-carousel-scroll-hint
0px
Inline padding that peeks the edges of adjacent slides — useful as a "there is more" affordance. Must include a unit (e.g.
2rem
).
--wf-carousel-slide-height
300px
Fixed height for slides in
vertical
orientation. Has no effect in horizontal mode.
Programmatic API & Events
Methods
Access the instance via
el._wfCarousel
after auto-init, or hold a reference returned by the constructor.
Method
Returns
Description
goToSlide(index, behavior)
void
Scroll to a slide by 0-based index.
behavior
:
'smooth'
(default) or
'auto'
.
next(behavior)
void
Advance by
slidesPerMove
. Wraps if loop is enabled.
previous(behavior)
void
Retreat by
slidesPerMove
. Wraps if loop is enabled.
getIndex()
number
Returns the current 0-based slide index.
getTotal()
number
Returns the total number of slides.
play()
void
Start or resume autoplay.
pause()
void
Pause autoplay until
play()
is called.
setDisabled(bool)
void
Enable or disable all interaction. Stops autoplay when
true
; restarts it (if configured) when
false
.
destroy()
void
Stop autoplay, disconnect the ResizeObserver, and remove all event listeners.
Events
Dispatched on the
.wf-carousel
wrapper element.
Event
Detail
Description
wf:slide-change
{ index, total }
Fires whenever the visible slide changes.
index
is 0-based;
total
is the full slide count.
JavaScript
import { WojoCarousel } from './src/js/components/wf-carousel.js'
// Manual init
const el = document.querySelector('[data-wf-carousel]')
const carousel = new WojoCarousel(el).init()
// Programmatic control
carousel.goToSlide(2) // Jump to third slide (smooth)
carousel.next() // Advance one step
carousel.previous('auto') // Retreat instantly (no animation)
console.log(carousel.getIndex(), '/', carousel.getTotal())
// Autoplay control
carousel.play()
carousel.pause()
// Via element reference (after auto-init)
const c = document.getElementById('my-carousel')._wfCarousel
c.setDisabled(true)
// Listen for slide changes
el.addEventListener('wf:slide-change', e => {
console.log(`Slide ${e.detail.index + 1} of ${e.detail.total}`)
})
Outer wrapper.
position:relative
container; set CSS custom properties here.
wf-carousel-item
Child
Each slide. Width is computed from
--wf-carousel-slides-per-page
. Override aspect ratio via
--wf-carousel-aspect-ratio
.
wf-carousel-stage
Generated
Intermediate wrapper created by JS that contains the track and nav buttons. Acts as the
position:relative
context for the buttons, ensuring they center against the track height only — not the total carousel height (which includes pagination).
wf-carousel-track
Generated
Scroll-snap flex track created by JS. Wraps all
.wf-carousel-item
children after init. Sits inside
.wf-carousel-stage
.
wf-carousel-btn-*
Generated
Circular nav buttons (
--prev
,
--next
). Generated when
data-wf-navigation
is set. Placed inside
.wf-carousel-stage
so
top:50%
centres on the track, not the pagination row. Add
data-wf-size="sm|lg"
to the wrapper for smaller or larger buttons.
wf-carousel-pagination
Generated
Dot indicator row placed directly on
.wf-carousel
, outside the stage, so it sits below the track without affecting button centering. In vertical mode it is
position:absolute
and floats at the inline-end edge instead. Generated when
data-wf-pagination
is set.
wf-carousel-dot
Generated
Individual pagination dot.
.is-active
marks the current slide and expands the dot to 1.25rem wide (or tall in vertical mode).
wf-carousel-counter
Optional
Absolute-positioned badge for slide position text (e.g., "2 / 5"). Not generated by JS — add it manually when needed.
wf-carousel--vertical
State
Added when
data-wf-orientation="vertical"
. Switches track to column flex and repositions nav buttons and pagination dots.
wf-carousel--disabled
State
Added by
setDisabled(true)
or
data-wf-disabled
. Dims the carousel (opacity 0.55) and blocks pointer events.
wf-carousel--ready
State
Added by JS after the first layout frame. Triggers track fade-in. Raw items are hidden until this class is present to prevent flash of unstyled content.
wf-carousel--mouse-dragging wf-carousel--dragging
State
--mouse-dragging
: shows grab cursor when idle.
--dragging
: switches to grabbing cursor and disables scroll-snap during an active drag.