YurbaSlider

YurbaSlider

A carousel that moves its slides with a transform: one or a group at a time, in a loop, centred, with drag, inertia and rubber-band edges. And a row that scrolls natively, for long lists swiped with a finger.

Usage
<link rel="stylesheet" href="/dist/yurba-slider.min.css">
<script src="/dist/yurba-slider.min.js"></script>

Give the slider the element whose children are the slides. It keeps its own classes and gap, and is wrapped in .y-slider.

<div class="cards">
    <div class="card">1</div>
    <div class="card">2</div>
    <div class="card">3</div>
</div>
const slider = new YurbaSlider('.cards', {
    slidesPerView: 3,
    spaceBetween: 16,
    loop: true,
})

slider.on('change', (index) => console.log('now at', index))

Slides added to the element later are picked up by themselves. A second slider on the same element destroys the first one.

Options
OptionTypeDescription
slidesPerView optionalnumber | 'auto'Slides in view. 'auto' keeps the width the slides have in CSS. Default: 'auto'.
slidesPerGroup optionalnumber | 'auto'Slides per step. 'auto' steps by what fits in view. Default: 1.
spaceBetween optionalnumberSpace between slides, px. Default: the element's CSS gap.
centered optionalbooleanThe current slide sits in the middle.
loop optionalbooleanEndless loop. It needs a spare slide on each side of the view, otherwise it stays off.
rewind optionalbooleanNext on the last slide goes back to the first one, and the other way round.
free optionalboolean | 'snap'Free scrolling with inertia. 'snap' settles on the nearest slide.
start optionalnumberSlide to start on. Default: 0.
speed optionalnumberMove duration, ms. Default: 420.
drag optionalbooleanDrag with the mouse and swipe on touch. Default: true.
grabCursor optionalbooleanGrab cursor over the slides.
threshold optionalnumberPixels before a drag starts. Default: 6.
resistance optionalnumberHow much the edges give when dragged past. Default: 0.35.
autoplay optionalnumberDelay between moves, ms. 0 is off. Pauses off screen, in a hidden tab, while dragging, on hover and on focus.
pauseOnHover optionalbooleanPause autoplay under the mouse. Default: true.
keyboard optionalbooleanLeft and right arrow keys while focus is inside. Default: true.
wheel optionalbooleanSideways trackpad swipes move the slides. Default: true.
arrows optionalboolean | objectBuilt-in arrows, or your own buttons. See Arrows. Default: true.
pagination optionalelement | string | objectDots, a fraction or a progress bar. See Pagination.
overflow optional'hidden' | 'visible''visible' lets slides show outside the slider. Default: 'hidden'.
breakpoints optionalobjectOptions by minimum window width. See Breakpoints.
icons optionalobjectHTML of the built-in arrows. See Icons.
labels optionalobjectAccessible names. See Labels.
on optionalobjectEvent handlers, e.g. { change: fn }.
Native row

With native: true the row scrolls natively: the browser's own swipe on touch, plus mouse drag and snapping. Best for long rows such as stories, shelves and tabs. The arrows step by a page.

new YurbaSlider(row, { native: true, snap: false, prevLabel: 'Back', nextLabel: 'Next' })
OptionTypeDescription
native requiredtrueTurns the native engine on.
items optionalelementContainer of the items, when it is not the scrolling element itself.
inset optionalnumberWhere items line up. Default: the left padding.
snap optionalbooleanSnap to items. Default: true.
slidesPerGroup optionalnumber | 'auto'The arrows step by a page, or by this many items. Default: 'auto'.
drag, arrows, icons, autoplay optionalmixedAs for the carousel. Autoplay goes page by page.
pagination / dots optionalelement | objectDots by page.
prevLabel, nextLabel optionalstringArrow labels.
onUpdate optionalfunctionCalled with { fits, start, end, page, pages }.
Breakpoints

Keys are minimum window widths. Every breakpoint the window has passed is applied on top of the base options.

new YurbaSlider('.cards', {
    slidesPerView: 1,
    breakpoints: {
        600: { slidesPerView: 2, slidesPerGroup: 2 },
        900: { slidesPerView: 3, slidesPerGroup: 3 },
    },
})

Live demo

Drag with the mouse, swipe sideways on a trackpad, or focus a slide and use the arrow keys.

One at a time
Groups

One, two or three in view by the window width, a whole group per step.

Loop & autoplay

Centred slides in an endless loop, moving every 3 seconds. Hover to pause.

Free mode

No snapping: a flick glides on and slows down.

Native row
Right to left

Controls

Mouse, touch & keys
InputAction
Drag or swipeMoves the slides and settles on the nearest one. A quick flick turns at least one slide. Past an end the slides give a little and spring back.
Vertical swipeLeft to the page, so it still scrolls.
Sideways trackpad swipeMoves the slides like a drag. Vertical wheel is left to the page.
← / →Previous / next while focus is inside the slider.
Tab to a hidden slideBrings that slide into view.
Click after a dragIgnored, so a drag never opens a link it started on.
Arrows

With arrows: true the slider draws its own arrows over the slides, shown on hover and hidden at the ends and on touch screens. To use your own buttons, pass them as elements or selectors: they get disabled at the ends. arrows: false leaves them out.

new YurbaSlider('.cards', {
    arrows: { prev: '.cards-prev', next: '.cards-next' },
})

API

update / destroy
MethodDescription
update()Measures again and keeps the current slide in place. Resizes and new slides call it by themselves.
destroy()Removes the slider and restores the element as it was.
State
PropertyTypeDescription
indexnumberThe current slide.
page, pagesnumberThe current page and how many there are.
slidesarrayThe slide elements.
isStart, isEndbooleanAt the first or the last step.
nativebooleanWhich engine runs.
YurbaSlider.get

The slider of an element, or null.

YurbaSlider.get('.cards')?.next()

Events

Overview

Subscribe with on(name, handler), or pass handlers in the on option. off(name, handler?) removes them. Every handler gets the slider as its last argument.

EventArgumentsWhen
initReady.
changeindexThe current slide changed.
moveprogressEvery frame of a move or a drag.
settleindexA move finished.
dragStart, dragEndvelocity on endA drag began or ended.
resizeMeasured again.
update{ fits, start, end, page, pages }Native row state changed.
destroyRemoved.
change
slider.on('change', (index) => {
    caption.textContent = captions[index]
})
move

progress runs from 0 at the first step to 1 at the last one, frame by frame.

slider.on('move', (progress) => {
    bar.style.transform = `scaleX(${progress})`
})
dragStart / dragEnd

velocity is in pixels per millisecond, positive forward.

slider.on('dragStart', () => video.pause())
slider.on('dragEnd', (velocity) => console.log(velocity))

Customization

Classes
ClassOn
.y-slider, --carousel, --nativeThe wrapper.
--start, --end, --fits, --dragging, --visible, --grabThe wrapper, by state.
.y-slider__track, --native, --snap, --draggingThe element given.
.y-slider__slide, .is-activeEach slide of a carousel.
.y-slider__arrow, --prev, --nextBuilt-in arrows.
.y-slider__pagination, --dots, --fraction, --progressThe pagination element.
.y-slider__dot, .y-slider__progressDots and the progress bar.
Icons

The built-in arrows take any HTML: an icon font, an SVG, an image. By default they are chevron_left and chevron_right from Material Symbols Rounded, which the page loads itself. Keys left out keep the default.

new YurbaSlider('.cards', {
    icons: {
        prev: '<span class="material-symbols-rounded">arrow_back</span>',
        next: '<svg viewBox="0 0 24 24" width="20" height="20"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2"/></svg>',
    },
})
KeyTypeDescription
prev optionalstringHTML of the previous arrow.
next optionalstringHTML of the next arrow.

Your own buttons passed in arrows keep their own content.

Labels

Accessible names, English by default. {index} and {total} are filled in.

new YurbaSlider('.cards', {
    labels: {
        prev: 'Назад',
        next: 'Далі',
        carousel: 'Новини',
        slide: '{index} з {total}',
        page: 'До слайда {index}',
    },
})

With reduced motion on, moves are instant and autoplay is off.