Skip to content

Repository files navigation

@mihnsen/vue-slick

A Vue 3 (Composition API + TypeScript) port of the Slick carousel, aiming for full parity with the react-slick settings API. Same DOM structure and CSS class names as the original, so slick's stylesheets — and most slick-based custom CSS — keep working.

Features

  • All ~40 react-slick settings, reactive at runtime: infinite loop, autoplay, fade, centerMode, vertical, RTL, variableWidth, adaptiveHeight, rows/slidesPerRow grid, responsive breakpoints (with 'unslick'), lazy loading, asNavFor synced carousels, and more
  • Touch & mouse drag with slick's swipe thresholds, edge friction, and swipeToSlide
  • Accessible: arrow-key navigation, aria-hidden management, dots as a tablist
  • SSR-safe (Nuxt 3): full markup server-rendered with no hydration mismatch
  • Zero runtime dependencies besides @vueuse/core; vue is a peer dependency
  • Ships typed: full TypeScript definitions for settings, events, and the exposed API

Install

npm i @mihnsen/vue-slick

vue (^3.4) is a peer dependency.

CSS

Import the functional stylesheet (layout: list/track/slide positioning, vertical mode, fade, pre-init state) and, optionally, the theme stylesheet (default arrow/dot styling — SVG data-URI icons, no font files):

import '@mihnsen/vue-slick/slick.css'
import '@mihnsen/vue-slick/slick-theme.css'

Both are plain CSS; no preprocessor required.

Usage

Slot + individual props

<script setup>
import { SlickCarousel } from '@mihnsen/vue-slick'
import '@mihnsen/vue-slick/slick.css'
import '@mihnsen/vue-slick/slick-theme.css'
</script>

<template>
  <SlickCarousel :dots="true" :infinite="true" :slides-to-show="3" :slides-to-scroll="1">
    <div v-for="i in 6" :key="i">Slide {{ i }}</div>
  </SlickCarousel>
</template>

settings object

<script setup>
import { SlickCarousel } from '@mihnsen/vue-slick'
import '@mihnsen/vue-slick/slick.css'
import '@mihnsen/vue-slick/slick-theme.css'

const settings = {
  dots: true,
  infinite: true,
  slidesToShow: 3,
  slidesToScroll: 1,
  responsive: [
    { breakpoint: 768, settings: { slidesToShow: 1 } },
  ],
}
</script>

<template>
  <SlickCarousel :settings="settings">
    <div v-for="i in 6" :key="i">Slide {{ i }}</div>
  </SlickCarousel>
</template>

Settings can be passed as the settings object prop, as individual typed props, or both — precedence is defaults → settings object → individual props → the currently matched responsive breakpoint. A responsive entry whose settings is the string 'unslick' renders the slides as a plain, unstyled list.

Two additional props sit outside Settings: asNavFor — a template ref to another mounted SlickCarousel instance to synchronize navigation with — and currentSlide (used with v-model:currentSlide) for controlled binding of the active slide index.

Settings

Name Type Default Description
accessibility boolean true Enables arrow-key navigation on the slider, aria-hidden on inactive/cloned slides, and role="tablist"/aria-selected on dots.
adaptiveHeight boolean false Resizes .slick-list to match the height of the current slide.
arrows boolean true Shows prev/next arrows (hidden automatically once slideCount <= slidesToShow).
autoplay boolean false Automatically advances slides on an interval.
autoplaySpeed number 3000 Milliseconds between auto-advances.
centerMode boolean false Centers the active slide with partial neighbor slides visible on both sides.
centerPadding string '50px' CSS length reserved on each side of the list in centerMode.
cssEase string 'ease' CSS transition-timing-function used for the track's transform transition.
dots boolean false Shows pagination dots below the slider (adds slick-dotted to the root element).
dotsClass string 'slick-dots' Class name applied to the dots <ul>.
draggable boolean true Enables mouse-drag dragging in addition to touch.
easing string 'linear' Accepted for react-slick API compatibility only — has no effect. See Limitations.
edgeFriction number 0.35 Resistance multiplier applied to drag movement past the first/last slide in finite mode.
fade boolean false Crossfades slides in place instead of sliding the track.
focusOnSelect boolean false Clicking a partially visible slide navigates to it.
infinite boolean true Wraps around at the ends using cloned slides.
initialSlide number 0 Index of the slide shown on mount.
lazyLoad 'ondemand' | 'progressive' | null null Enables data-lazy image loading — 'ondemand' promotes images as their slide becomes active, 'progressive' loads all of them in the background after mount.
mobileFirst boolean false When true, responsive breakpoints match viewport widths >= the breakpoint instead of <=.
pauseOnDotsHover boolean false Pauses autoplay while hovering the dots.
pauseOnFocus boolean true Pauses autoplay while the slider has focus.
pauseOnHover boolean true Pauses autoplay while hovering the slider.
responsive { breakpoint: number, settings: Partial<Settings> | 'unslick' }[] | null null Breakpoint-specific setting overrides; 'unslick' renders a plain unstyled list at that breakpoint.
respondTo 'window' | 'slider' | 'min' 'window' Which width drives responsive breakpoint matching — the window, the slider container, or the smaller of the two.
rows number 1 Number of rows per slide group (grid mode); combine with slidesPerRow.
rtl boolean false Right-to-left layout; also flips which arrow key navigates forward/back.
slidesPerRow number 1 Number of slides per row when rows > 1.
slidesToShow number 1 Number of slides visible at once.
slidesToScroll number 1 Number of slides advanced per navigation.
speed number 500 Transition duration in milliseconds.
swipe boolean true Enables touch/pointer swipe navigation.
swipeToSlide boolean false Lets a drag land on any slide (nearest-slide snap) rather than always moving by slidesToScroll.
touchMove boolean true Gates the whole drag/swipe layer: false disables pointer dragging entirely (not just the visual "follow the finger" motion). Splitting that from swipe for full react-slick parity is a deferred fast-follow.
touchThreshold number 5 Divisor of the list width used to compute the drag distance required to trigger navigation.
useCSS boolean true Enables the CSS transition on the track/slide; false makes changes apply instantly.
useTransform boolean true Positions the track with transform: translate3d; false uses left/top instead (still CSS-transitioned).
variableWidth boolean false Slides size to their own content width instead of an even split of the list.
vertical boolean false Stacks and navigates slides vertically instead of horizontally.
verticalSwiping boolean false Enables vertical-axis dragging when vertical is true.
waitForAnimate boolean true Ignores new navigation requests while a transition is already in progress.

Events

Event Payload Fires when
init — The carousel has mounted.
re-init — The matched responsive breakpoint entry changes.
before-change (from: number, to: number) Just before the current slide changes.
after-change (current: number) After a slide change completes.
edge (direction: 'left' | 'right') Navigation is attempted past the first/last slide in finite mode.
swipe (direction: string) A drag/swipe gesture completes.
lazy-load (indexes: number[]) data-lazy images finish loading for the given slide indexes.
lazy-load-error (index: number) A data-lazy image fails to load.
update:currentSlide (index: number) The active slide index changes — pair with v-model:currentSlide.

Exposed methods

Access via a template ref on <SlickCarousel ref="slick">:

Method Description
next() Advance by slidesToScroll.
prev() Go back by slidesToScroll.
goTo(index: number, dontAnimate?: boolean) Jump to a specific slide index.
play() (Re)start autoplay.
pause() Stop autoplay.
currentSlide Read-only current slide index.

goToUnsync(index) is also exposed; it exists to support asNavFor synchronization (it navigates without propagating back to a linked carousel, preventing ping-pong) and is not intended for direct use.

Slots

Slot Props Purpose
default — Slide content — one child per slide (v-for works).
prev-arrow { disabled, onClick } Replace the prev arrow's markup.
next-arrow { disabled, onClick } Replace the next arrow's markup.
dots { dots: { count, current } } Replace the whole dots list (equivalent to react-slick's appendDots).
custom-paging { index } Replace an individual dot's content (equivalent to customPaging(i)).

Limitations

  • easing (jQuery-animation easing name in the original slick/react-slick) is accepted for API compatibility but is a documented no-op — this port drives transitions with native CSS transitions, and cssEase is the supported control for the timing curve.
  • useCSS: false and useTransform: false are honored (see the settings table above) but are legacy escape hatches carried over from react-slick, not the recommended path.

SSR / Nuxt 3

SlickCarousel is SSR-safe and works out of the box with Nuxt 3: the full slide markup — including infinite-mode clones and arrows/dots — renders deterministically on the server using slick's own percentage-based sizing trick (track width = slideCount * 100 / slidesToShow%, each slide = 100 / totalPositions% of the track), which needs no layout measurement. All real measurement, event listeners, and VueUse browser utilities activate on the client in onMounted, so there is no window/document access during server rendering and no hydration mismatch. The slick-initialized class is added client-side only, once mounted.

Development

npm install
npm run dev        # playground: pages for basic, drag, layout modes, autoplay, synced nav
npm test           # vitest (jsdom + node SSR suite)
npm run typecheck  # vue-tsc
npm run build      # library build to dist/ (ES + UMD + d.ts + css)

License

MIT

About

Vue 3 port of the Slick carousel with full react-slick API parity — Composition API, TypeScript, SSR-safe

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages