# Splide

> Migrate from Splide to Blossom Carousel by replacing Splide tracks, lists, options, and events with native scrolling and CSS.

Splide builds a carousel from a root element, track, list, slide elements, options, extensions, and a JavaScript instance.

Blossom keeps the carousel as a native scroll container. Layout, slide sizing, gaps, snapping, and responsive behavior belong in CSS, while Blossom adds dragging and small convenience methods.

## Migration mindset

When moving from Splide to Blossom, migrate the carousel in three steps:

1. Replace the Splide root, track, and list structure with a single `<BlossomCarousel>` root.
2. Move Splide options such as `perPage`, `gap`, `focus`, `direction`, and `breakpoints` into CSS.
3. Replace Splide instance calls and events with Blossom methods, native scroll APIs, and browser observers.

<note color="neutral" icon="i-lucide-lightbulb">

Splide migrations usually remove wrapper markup. The Blossom carousel root is the element that scrolls.

</note>

## Installation

Remove Splide and install the matching Blossom package for your framework.

<code-group sync="migration-code-style">

```bash [Vue]
npm uninstall @splidejs/vue-splide @splidejs/splide
npm install @blossom-carousel/vue
```

```bash [React]
npm uninstall @splidejs/react-splide @splidejs/splide
npm install @blossom-carousel/react
```

```bash [Svelte]
npm uninstall @splidejs/svelte-splide @splidejs/splide
npm install @blossom-carousel/svelte
```

```bash [Core]
npm uninstall @splidejs/splide
npm install @blossom-carousel/core
```

</code-group>

Import the stylesheet from your framework package once in your app.

<code-group>

```js [Vue]
import "@blossom-carousel/vue/style.css";
```

```js [React]
import "@blossom-carousel/react/style.css";
```

```js [Svelte]
import "@blossom-carousel/svelte/style.css";
```

```js [Core]
import "@blossom-carousel/core/style.css";
```

```js [Web]
import "@blossom-carousel/web/style.css";
```

</code-group>

## Component structure

Splide usually needs a root, track, list, and slide elements. Blossom uses one scroll container with direct slide children.

<code-group sync="migration-code-style">

```vue [Vue]
<script setup lang="ts">
import { Splide, SplideSlide } from "@splidejs/vue-splide"; // [!code --]
import "@splidejs/vue-splide/css"; // [!code --]
import { BlossomCarousel } from "@blossom-carousel/vue"; // [!code ++]
import "@blossom-carousel/vue/style.css"; // [!code ++]
</script>

<template>
  <Splide :options="{ perPage: 4, gap: '1rem' }"> <!-- [!code --] -->
    <SplideSlide>Slide 1</SplideSlide> <!-- [!code --] -->
    <SplideSlide>Slide 2</SplideSlide> <!-- [!code --] -->
    <SplideSlide>Slide 3</SplideSlide> <!-- [!code --] -->
  </Splide> <!-- [!code --] -->
  <BlossomCarousel class="carousel grid! grid-auto-cols grid-cols-[calc((100% - 3rem) / 4)] gap-4"> <!-- [!code ++] -->
    <div class="slide snap-start">Slide 1</div> <!-- [!code ++] -->
    <div class="slide snap-start">Slide 2</div> <!-- [!code ++] -->
    <div class="slide snap-start">Slide 3</div> <!-- [!code ++] -->
  </BlossomCarousel> <!-- [!code ++] -->
</template>
```

```tsx [React]
import { Splide, SplideSlide } from "@splidejs/react-splide"; // [!code --]
import "@splidejs/react-splide/css"; // [!code --]
import { BlossomCarousel } from "@blossom-carousel/react"; // [!code ++]
import "@blossom-carousel/react/style.css"; // [!code ++]

export function Carousel() {
  return (
    <Splide options={{ perPage: 4, gap: "1rem" }}> {/* [!code --] */}
      <SplideSlide>Slide 1</SplideSlide> {/* [!code --] */}
      <SplideSlide>Slide 2</SplideSlide> {/* [!code --] */}
      <SplideSlide>Slide 3</SplideSlide> {/* [!code --] */}
    </Splide> {/* [!code --] */}
    <BlossomCarousel className="carousel grid! grid-auto-cols grid-cols-[calc((100% - 3rem) / 4)] gap-4"> {/* [!code ++] */}
      <div className="slide snap-start">Slide 1</div> {/* [!code ++] */}
      <div className="slide snap-start">Slide 2</div> {/* [!code ++] */}
      <div className="slide snap-start">Slide 3</div> {/* [!code ++] */}
    </BlossomCarousel> {/* [!code ++] */}
  );
}
```

```svelte [Svelte]
<script>
  import { Splide, SplideSlide } from "@splidejs/svelte-splide"; // [!code --]
  import "@splidejs/svelte-splide/css"; // [!code --]
  import { BlossomCarousel } from "@blossom-carousel/svelte"; // [!code ++]
  import "@blossom-carousel/svelte/style.css"; // [!code ++]

  const options = { perPage: 4, gap: "1rem" }; // [!code --]
</script>

<Splide {options}> <!-- [!code --] -->
  <SplideSlide>Slide 1</SplideSlide> <!-- [!code --] -->
  <SplideSlide>Slide 2</SplideSlide> <!-- [!code --] -->
  <SplideSlide>Slide 3</SplideSlide> <!-- [!code --] -->
</Splide> <!-- [!code --] -->
<BlossomCarousel class="carousel grid! grid-auto-cols grid-cols-[calc((100% - 3rem) / 4)] gap-4"> <!-- [!code ++] -->
  <div class="slide snap-start">Slide 1</div> <!-- [!code ++] -->
  <div class="slide snap-start">Slide 2</div> <!-- [!code ++] -->
  <div class="slide snap-start">Slide 3</div> <!-- [!code ++] -->
</BlossomCarousel> <!-- [!code ++] -->
```

```html [Core]
<div class="splide"> <!-- [!code --] -->
  <div class="splide__track"> <!-- [!code --] -->
    <ul class="splide__list"> <!-- [!code --] -->
      <li class="splide__slide">Slide 1</li> <!-- [!code --] -->
      <li class="splide__slide">Slide 2</li> <!-- [!code --] -->
      <li class="splide__slide">Slide 3</li> <!-- [!code --] -->
    </ul> <!-- [!code --] -->
  </div> <!-- [!code --] -->
</div> <!-- [!code --] -->
<blossom-carousel class="carousel grid! grid-auto-cols grid-cols-[calc((100% - 3rem) / 4)] gap-4"> <!-- [!code ++] -->
  <div class="slide snap-start">Slide 1</div> <!-- [!code ++] -->
  <div class="slide snap-start">Slide 2</div> <!-- [!code ++] -->
  <div class="slide snap-start">Slide 3</div> <!-- [!code ++] -->
</blossom-carousel> <!-- [!code ++] -->
```

</code-group>

## Options

Splide options describe slide movement, sizing, and generated controls. In Blossom, those choices usually become CSS and small browser APIs.

<table>
<thead>
  <tr>
    <th>
      Splide concept
    </th>
    
    <th>
      Blossom approach
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        perPage
      </code>
    </td>
    
    <td>
      Use CSS <code>
        grid-auto-columns
      </code>
      
       to define the relative width of slides.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        perMove
      </code>
    </td>
    
    <td>
      Use CSS <code>
        scroll-snap-align
      </code>
      
       within <code>
        :nth-child(xn)
      </code>
      
       or nest slides in groups.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gap
      </code>
    </td>
    
    <td>
      Use CSS <code>
        gap
      </code>
      
       in a <code>
        grid
      </code>
      
       or <code>
        flex
      </code>
      
       layout.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        focus: "center"
      </code>
    </td>
    
    <td>
      Use <code>
        scroll-snap-align: center
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        direction
      </code>
    </td>
    
    <td>
      Use <code>
        dir="rtl"
      </code>
      
       or CSS <code>
        direction: rtl
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        breakpoints
      </code>
    </td>
    
    <td>
      Use CSS media queries and container queries.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        type: "loop"
      </code>
    </td>
    
    <td>
      Prefer bounded native scrolling, or use the experimental repeat pattern when an infinite effect is required. See <a href="/docs/examples/experimental/repeat">
        Repeat example
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        drag: "free"
      </code>
    </td>
    
    <td>
      Omit <code>
        scroll-snap-align
      </code>
      
       or use <code>
        scroll-snap-type: proximity
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        arrows
      </code>
    </td>
    
    <td>
      Use <code>
        <BlossomPrev>
      </code>
      
       and <code>
        <BlossomNext>
      </code>
      
      . See <a href="/docs/examples/basic/buttons">
        Buttons example
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pagination
      </code>
    </td>
    
    <td>
      Use <code>
        <BlossomDots for="my-carousel">
      </code>
      
       and mark slides with <code>
        data-blossom-slide
      </code>
      
      . See <a href="/docs/examples/basic/dots">
        Dots example
      </a>
      
      .
    </td>
  </tr>
</tbody>
</table>

For example, this Splide setup:

```js [Splide]
new Splide(".splide", {
  perPage: 1,
  gap: "1rem",
  focus: "center",
  breakpoints: {
    768: { perPage: 3 },
  },
}).mount();
```

becomes CSS:

```css [Blossom]
.carousel {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  gap: 1rem;
  scroll-snap-type: inline mandatory;
}

.slide {
  scroll-snap-align: center;
}

@media (min-width: 768px) {
  .carousel {
    grid-auto-columns: calc((100% - 2rem) / 3);
  }
}
```

## Controls

Splide controls call methods on the Splide instance. Blossom provides `<BlossomPrev>`, `<BlossomNext>`, and `<BlossomDots>` components that link to the carousel through matching `id` and `for` props.

```ts
splide.go("<"); // [!code --]
splide.go(">"); // [!code --]
```

```html
<BlossomCarousel id="gallery" class="carousel">
  <div data-blossom-slide class="slide">Slide 1</div>
  ...
</BlossomCarousel>

<div class="controls">
  <BlossomPrev for="gallery" />
  <BlossomNext for="gallery" />
</div>

<BlossomDots for="gallery" />
```

For direct slide navigation, call `goTo(index)` on the carousel. It scrolls to the slide at that zero-based index, counting slides marked with `data-blossom-slide`. Reach the carousel through a template ref in Vue, a `ref` in React, `bind:this` in Svelte, or the `<blossom-carousel>` element itself.

```ts
carousel.goTo(index);
carousel.goTo(index, { behavior: "instant" });
```

## API

Splide commonly uses `moved` or `active` events to track the current slide.

With Blossom, read the active slide from `useBlossomNavigation` in Vue, React, and Svelte. Pass the carousel `id`; it returns `activeIndex`, `count`, `canPrev`, and `canNext`, and updates during drag and free scrolling too.

```ts
splide.on("moved", (newIndex) => { // [!code --]
  setSelectedIndex(newIndex); // [!code --]
}); // [!code --]

const nav = useBlossomNavigation("gallery"); // [!code ++]
```

In React and Svelte, read `nav.activeIndex`. In Vue, `nav` is a ref, so read `nav.value.activeIndex` in script or `nav.activeIndex` in the template. Don't destructure the result in Svelte; that loses reactivity.

With Web Components, listen for the native `scrollsnapchange` event where it's supported:

```ts
const slides = Array.from(carousel.querySelectorAll("[data-blossom-slide]"));

carousel.addEventListener("scrollsnapchange", (event) => {
  setSelectedIndex(slides.indexOf(event.snapTargetInline));
});
```

## Extensions

Splide extensions and built-in UI usually become small Blossom wrappers or native platform features.

<table>
<thead>
  <tr>
    <th>
      Splide pattern
    </th>
    
    <th>
      Blossom replacement
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Arrows
    </td>
    
    <td>
      <code>
        <BlossomPrev>
      </code>
      
       and <code>
        <BlossomNext>
      </code>
      
       components.
    </td>
  </tr>
  
  <tr>
    <td>
      Pagination
    </td>
    
    <td>
      <code>
        <BlossomDots>
      </code>
      
       with <code>
        data-blossom-slide
      </code>
      
       on slides.
    </td>
  </tr>
  
  <tr>
    <td>
      Autoplay
    </td>
    
    <td>
      A manual timer that scrolls the next slide into view.
    </td>
  </tr>
  
  <tr>
    <td>
      Auto width
    </td>
    
    <td>
      Let slide content size itself with CSS.
    </td>
  </tr>
  
  <tr>
    <td>
      Auto height
    </td>
    
    <td>
      Let content define height, or update layout with <code>
        ResizeObserver
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      Grid / rows
    </td>
    
    <td>
      CSS grid.
    </td>
  </tr>
  
  <tr>
    <td>
      Lazy load
    </td>
    
    <td>
      Native <code>
        loading="lazy"
      </code>
      
       and <code>
        content-visibility: auto
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

Keep extension migrations small. Start from a working Blossom carousel, then add behavior only if the product still needs it.

## Lifecycle

Splide's and Blossom's lifecycle methods are similar.

<note color="neutral" icon="i-lucide-lightbulb">

Blossom initializes automatically when using framework components.

</note>

```ts
splide.refresh(); // [!code --]
splide.destroy(); // [!code --]
blossom.init(); // [!code ++]
blossom.destroy(); // [!code ++]
```

## Migration checklist

- Remove Splide packages and install the matching Blossom package.
- Import the stylesheet from your framework package once (for example `@blossom-carousel/vue/style.css`).
- Replace Splide root, track, list, and slide wrappers with `<BlossomCarousel>` and direct slide children.
- Move slide sizing, gaps, snapping, direction, focus, and breakpoints into CSS.
- Replace `go("<")` and `go(">")` with `<BlossomPrev>` and `<BlossomNext>`.
- Replace `go(index)` with `goTo(index)` on the carousel.
- Replace Splide events with `useBlossomNavigation` (or `scrollsnapchange` for Web Components).
- Rebuild only the Splide extensions your carousel still needs.

## Next steps

- [Installation](/docs/getting-started/installation) - Pick the package for your framework.
- [Snapping](/docs/examples/basic/snap) - Configure scroll snap behavior with CSS.
- [Buttons](/docs/examples/basic/buttons) - Add previous and next controls.
- [Dots](/docs/examples/basic/dots) - Add dot markers with `<BlossomDots>`.
- [Repeat](/docs/examples/experimental/repeat) - Explore an experimental repeating carousel pattern.
