# Flickity

> Migrate from Flickity to Blossom Carousel by replacing Flickity cells, options, and events with native scrolling and CSS.

Flickity creates a carousel from cell elements, option objects, generated controls, selected-cell state, and a JavaScript instance.

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

## Migration mindset

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

1. Replace Flickity initialization with a single `<BlossomCarousel>` root and direct children.
2. Move Flickity options such as `cellAlign`, `contain`, `wrapAround`, and `groupCells` into CSS or native scrolling.
3. Replace Flickity methods and events with Blossom methods, native scroll APIs, and browser observers.

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

Flickity migrations work best when you treat each cell as a normal scroll-snap child instead of a measured item in a carousel engine.

</note>

## Installation

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

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

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

```bash [React]
npm uninstall react-flickity-component flickity
npm install @blossom-carousel/react
```

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

```bash [Core]
npm uninstall flickity
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

Flickity initializes behavior on an element and treats its children as cells. Blossom keeps that direct-child model, but the root itself is the native scroll container.

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

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

<template>
  <Flickity :options="{ cellAlign: "left", contain: true }"> <!-- [!code --] -->
    <div class="carousel-cell">Slide 1</div> <!-- [!code --] -->
    <div class="carousel-cell">Slide 2</div> <!-- [!code --] -->
    <div class="carousel-cell">Slide 3</div> <!-- [!code --] -->
  </Flickity> <!-- [!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 Flickity from "react-flickity-component"; // [!code --]
import "flickity/css/flickity.css"; // [!code --]
import { BlossomCarousel } from "@blossom-carousel/react"; // [!code ++]
import "@blossom-carousel/react/style.css"; // [!code ++]

export function Carousel() {
  return (
    <Flickity options={{ cellAlign: "left", contain: true }}> {/* [!code --] */}
      <div className="carousel-cell">Slide 1</div> {/* [!code --] */}
      <div className="carousel-cell">Slide 2</div> {/* [!code --] */}
      <div className="carousel-cell">Slide 3</div> {/* [!code --] */}
    </Flickity> {/* [!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 { onMount } from "svelte"; // [!code --]
  import Flickity from "flickity"; // [!code --]
  import "flickity/css/flickity.css"; // [!code --]
  import { BlossomCarousel } from "@blossom-carousel/svelte"; // [!code ++]
  import "@blossom-carousel/svelte/style.css"; // [!code ++]

  let carousel; // [!code --]

  onMount(() => { // [!code --]
    const flickity = new Flickity(carousel, { cellAlign: "left", contain: true }); // [!code --]
    return () => flickity.destroy(); // [!code --]
  }); // [!code --]
</script>

<div class="carousel" bind:this={carousel}> <!-- [!code --] -->
  <div class="carousel-cell">Slide 1</div> <!-- [!code --] -->
  <div class="carousel-cell">Slide 2</div> <!-- [!code --] -->
  <div class="carousel-cell">Slide 3</div> <!-- [!code --] -->
</div> <!-- [!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="carousel"> <!-- [!code --] -->
  <div class="carousel-cell">Slide 1</div> <!-- [!code --] -->
  <div class="carousel-cell">Slide 2</div> <!-- [!code --] -->
  <div class="carousel-cell">Slide 3</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

Flickity options describe how its engine measures and aligns cells. In Blossom, most of those choices become CSS and native scroll behavior.

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

<tbody>
  <tr>
    <td>
      <code>
        cellAlign: "left"
      </code>
    </td>
    
    <td>
      Use <code>
        scroll-snap-align: start
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cellAlign: "center"
      </code>
    </td>
    
    <td>
      Use <code>
        scroll-snap-align: center
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contain
      </code>
    </td>
    
    <td>
      Use native scroll bounds, padding, and <code>
        scroll-padding
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        groupCells
      </code>
    </td>
    
    <td>
      Create grouped slide elements or use native scrolling to target every nth slide.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        wrapAround
      </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>
        freeScroll
      </code>
    </td>
    
    <td>
      Omit <code>
        scroll-snap-align
      </code>
      
       or use <code>
        scroll-snap-type: proximity
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rightToLeft
      </code>
    </td>
    
    <td>
      Use <code>
        dir="rtl"
      </code>
      
       or CSS <code>
        direction: rtl
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        adaptiveHeight
      </code>
    </td>
    
    <td>
      Let content define height, or update layout with <code>
        ResizeObserver
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prevNextButtons
      </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>
        pageDots
      </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 Flickity setup:

```js [Flickity]
const flkty = new Flickity(".carousel", {
  cellAlign: "center",
  contain: true,
  groupCells: true,
  wrapAround: false,
});
```

becomes CSS:

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

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

## Controls

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

```ts
flkty.previous(); // [!code --]
flkty.next(); // [!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

Flickity commonly uses the `select` event and `selectedIndex` to track the active cell.

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
flkty.on("select", () => { // [!code --]
  setSelectedIndex(flkty.selectedIndex); // [!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));
});
```

## Features

Flickity features usually become either small Blossom wrappers or native platform features.

<table>
<thead>
  <tr>
    <th>
      Flickity feature
    </th>
    
    <th>
      Blossom replacement
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Previous / next buttons
    </td>
    
    <td>
      <code>
        <BlossomPrev>
      </code>
      
       and <code>
        <BlossomNext>
      </code>
      
       components.
    </td>
  </tr>
  
  <tr>
    <td>
      Page dots
    </td>
    
    <td>
      <code>
        <BlossomDots>
      </code>
      
       with <code>
        data-blossom-slide
      </code>
      
       on slides.
    </td>
  </tr>
  
  <tr>
    <td>
      Auto play
    </td>
    
    <td>
      A manual timer that scrolls the next slide into view.
    </td>
  </tr>
  
  <tr>
    <td>
      Lazy load
    </td>
    
    <td>
      Native <code>
        loading="lazy"
      </code>
      
       and <code>
        content-visibility: auto
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      As nav for
    </td>
    
    <td>
      Shared selected state plus <code>
        goTo()
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      Images loaded
    </td>
    
    <td>
      Native image loading events or <code>
        ResizeObserver
      </code>
      
       if layout depends on image size.
    </td>
  </tr>
  
  <tr>
    <td>
      Fade
    </td>
    
    <td>
      CSS scroll-driven animations or intersection state.
    </td>
  </tr>
</tbody>
</table>

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

## Lifecycle

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

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

Blossom initializes automatically when using framework components.

</note>

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

## Migration checklist

- Remove Flickity packages and install the matching Blossom package.
- Import the stylesheet from your framework package once (for example `@blossom-carousel/vue/style.css`).
- Replace Flickity initialization with `<BlossomCarousel>` and direct slide children.
- Move cell sizing, alignment, gaps, snapping, direction, and breakpoints into CSS.
- Replace `previous()` and `next()` with `<BlossomPrev>` and `<BlossomNext>`.
- Replace `select(index)` with `goTo(index)` on the carousel.
- Replace Flickity events with `useBlossomNavigation` (or `scrollsnapchange` for Web Components).
- Rebuild only the Flickity features 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.
