@blossom-carousel/vue

A native-scroll-first carousel component for Vue.
9,694 1,052
Install
npm install @blossom-carousel/vue
Latest Version:1.8.0
Vue:3
License:MIT
Last Updated:Oct 20, 2026
Links: GitHub  ·  npm
Maintainer: jespervos

Blossom Carousel

A native-scroll-first carousel enhanced with drag support for Vue.

Installation

npm install @blossom-carousel/vue

Full installation instructions

Vue
import { BlossomCarousel } from "@blossom-carousel/vue";
import "@blossom-carousel/vue/style.css";

const app = createApp({});
app.component("BlossomCarousel", BlossomCarousel);
Nuxt

Install globally plugins/blossom-carousel.js

import { BlossomCarousel } from "@blossom-carousel/vue";
import "@blossom-carousel/vue/style.css";

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.component("BlossomCarousel", BlossomCarousel);
});

Usage

<BlossomCarousel>
  <div v-for="i in 12">Slide {{ i }}</div>
</BlossomCarousel>

as

Define the HTMLElement of the carousel root.

<BlossomCarousel as="ul">
  <li v-for="i in 12">Slide {{ i }}</li>
</BlossomCarousel>

Renders as

<ul>
  <li>Slide 1</li>
  <li>Slide 2</li>
  <li>Slide 3</li>
  ...
</ul>

Navigation controls

Place previous, next, and dot controls outside the carousel with <BlossomPrev>, <BlossomNext>, and <BlossomDots>. Link them to the carousel with an id on <BlossomCarousel>, and a matching for prop on each control and mark slides with data-blossom-slide.

<BlossomCarousel id="my-carousel">
  <div v-for="i in 12" :key="i" data-blossom-slide>Slide {{ i }}</div>
</BlossomCarousel>

<BlossomPrev for="my-carousel" />
<BlossomDots for="my-carousel" />
<BlossomNext for="my-carousel" />
Prev/Next Buttons

<BlossomPrev> and <BlossomNext> are aware of configured scroll-snap and will navigate between snap points. When no scroll-snap is configured, they will slide they carousel proportionally.

Slot your own content to replace the default button icon.

<BlossomPrev for="my-carousel">
  <span>Previous</span>
</BlossomPrev>
Custom navigation UI

useNavigation exposes the same reactive state the built-in controls use. Pass a string, a ref, or undefined:

<script setup>
import { useId } from "vue";
import { useNavigation } from "@blossom-carousel/vue";

const carouselId = useId();
const state = useNavigation(carouselId);
</script>

state is a ref with canPrev, canNext, activeIndex, and count.

Dots

<BlossomDots> renders one button per slide marked with data-blossom-slide. Default styles can be themed with CSS custom properties on the component or any ancestor:

/* defaults */
--blossom-dot-size: 0.625rem;
--blossom-dot-radius: 50%;
--blossom-dot-color: currentColor;
--blossom-dot-opacity: 0.35;
--blossom-dot-hover-opacity: 0.6;
--blossom-dot-active-opacity: 1;

To bring your own dots, provide a default slot and render <BlossomDot> inside it. This will configure the dot as a <button> with navigation wired up. Now you can style the dot as you please and attach any button attributes you need.

<BlossomDots for="my-carousel" v-slot="{ index, active }">
  <BlossomDot
    class="my-dot"
    :data-active="active"
    :aria-label="`Photo ${index + 1}`"
  >
    {{ index + 1 }}
  </BlossomDot>
</BlossomDots>
Scroll behavior

Every navigation control scrolls smoothly by default. Set the behavior prop to "instant" or "auto" to change that. On <BlossomDots> it applies to every dot; a <BlossomDot> can override it for itself.

<BlossomPrev for="my-carousel" behavior="instant" />
<BlossomDots for="my-carousel" behavior="instant" />
<BlossomNext for="my-carousel" behavior="instant" />

The prop is rendered as a data-blossom-behavior attribute on the button. Setting that attribute yourself takes precedence over the prop.

Listening for commands

Listen for command events on the carousel to know when any navigation control is triggered or a method is called:

  • previous (--blossom-prev)
  • next (--blossom-next)
  • dot (--blossom-goto-{index}).

These events are not fired by drag or free scrolling. Read event.command (or event.detail.command where the Invoker Commands polyfill applies).

<BlossomCarousel @command="handleCommand">
  <div v-for="i in 12" :key="i" data-blossom-slide>Slide {{ i }}</div>
</BlossomCarousel>

<script setup lang="ts">
const handleCommand = (event: CustomEvent) => {
  const command = event?.command || event?.detail?.command;
};
</script>
Global registration

Register the components alongside BlossomCarousel:

import {
  BlossomCarousel,
  BlossomPrev,
  BlossomNext,
  BlossomDots,
  BlossomDot,
  useNavigation,
} from "@blossom-carousel/vue";
import "@blossom-carousel/vue/style.css";

const app = createApp({});
app.component("BlossomCarousel", BlossomCarousel);
app.component("BlossomPrev", BlossomPrev);
app.component("BlossomNext", BlossomNext);
app.component("BlossomDots", BlossomDots);
app.component("BlossomDot", BlossomDot);

Methods

Get a template ref to <BlossomCarousel> to navigate from your own code:

  • prev(options?) scrolls to the previous snap point or page.
  • next(options?) scrolls to the next snap point or page.
  • goTo(index, options?) scrolls to the slide at a zero-based index, counting slides marked with data-blossom-slide.
  • el is a ref to the carousel's root element.

options.behavior accepts "smooth" (default), "instant" or "auto". The methods use native scrolling, so they also work on touch devices where the drag engine isn't loaded.

<script setup>
import { useTemplateRef } from "vue";

const carousel = useTemplateRef("carousel");
</script>

<template>
  <BlossomCarousel ref="carousel">
    <div v-for="i in 12" :key="i" data-blossom-slide>Slide {{ i }}</div>
  </BlossomCarousel>

  <button @click="carousel.goTo(0, { behavior: 'instant' })">Back to start</button>
</template>

Overscroll API

Tap into Blossom's drag engine's overscroll behavior to create your own style.

<template>
  <!-- prevent and overwrite Blossom's default rubberbanding effect -->
  <BlossomCarousel @overscroll.prevent="onOverscroll">
    <div v-for="i in 12" :key="i">Slide {{ i }}</div>
  </BlossomCarousel>
</template>

<script setup>
function onOverscroll(event) {
  const overScroll = event.detail.left;

  Array.from(blossomCarousel.value.children).forEach((slide) => {
    slide.style.transform = `scale(${1 - overScroll * 0.1})`;
  });
}
</script>

Examples

Explore ready-to-copy carousel patterns grouped by complexity.

See all examples

Related Packages

@blossom-carousel/web

A native-scroll-first carousel component for the web.

23,472 1,052
embla-carousel-aria

An accessibility plugin for Embla Carousel

29,236 14
embla-carousel

A lightweight carousel library with fluid motion and great swipe precision

1,138,077,498 8,453
embla-carousel-reactive-utils

Reactive utilities for Embla Carousel

1,100,861,544 8,453
embla-carousel-autoplay

An autoplay plugin for Embla Carousel

96,012,888 8,453

Version History

Version Released Vue License
1.8.0 ^3.5.13 MIT
1.7.0 ^3.5.13 MIT
1.6.1 ^3.5.13 MIT
1.6.0 ^3.5.13 MIT
1.5.3 ^3.5.13 MIT