@mihnsen/vue-slick
v0.1.0
Published
Vue 3 port of the Slick carousel with full react-slick API parity — Composition API, TypeScript, SSR-safe
Downloads
69
Maintainers
Readme
@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,asNavForsynced carousels, and more - Touch & mouse drag with slick's swipe thresholds, edge friction, and
swipeToSlide - Accessible: arrow-key navigation,
aria-hiddenmanagement, dots as atablist - SSR-safe (Nuxt 3): full markup server-rendered with no hydration mismatch
- Zero runtime dependencies besides
@vueuse/core;vueis a peer dependency - Ships typed: full TypeScript definitions for settings, events, and the exposed API
Install
npm i @mihnsen/vue-slickvue (^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, andcssEaseis the supported control for the timing curve.useCSS: falseanduseTransform: falseare 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)