Blossom Carousel Logo
GitHub
Framework Guides

Svelte and SvelteKit

Use Blossom Carousel in Svelte and SvelteKit with keyed each blocks and global stylesheet imports.

Install

pnpm add @blossom-carousel/svelte

Svelte usage

@blossom-carousel/svelte2.x requires Svelte 5 (runes + snippets) and drops Svelte 4 support. If you're on Svelte 4, stay on @blossom-carousel/svelte@1.
<script>
  import { BlossomCarousel } from "@blossom-carousel/svelte";
  import "@blossom-carousel/svelte/style.css";

  const slides = Array.from({ length: 12 }, (_, index) => index + 1);
</script>

<BlossomCarousel>
  {#each slides as slide (slide)}
    <div>Slide {slide}</div>
  {/each}
</BlossomCarousel>

SvelteKit setup

Import the stylesheet from the root layout.

src/routes/+layout.svelte
<script>
  import "@blossom-carousel/svelte/style.css";

  let { children } = $props();
</script>

{@render children()}

Then import the component in the page or component that renders the carousel.

<script>
  import { BlossomCarousel } from "@blossom-carousel/svelte";
</script>

<BlossomCarousel>{/* slides */}</BlossomCarousel>

Semantic root element

Use as="ul" for list-like carousels.

<BlossomCarousel as="ul">
  {#each slides as slide (slide)}
    <li>Slide {slide}</li>
  {/each}
</BlossomCarousel>

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 forId prop on each control and mark slides with data-blossom-slide.

<BlossomCarousel id="my-carousel">
  {#each slides as slide (slide)}
    <div data-blossom-slide>Slide {slide}</div>
  {/each}
</BlossomCarousel>

<BlossomPrev forId="my-carousel" />
<BlossomDots forId="my-carousel" />
<BlossomNext forId="my-carousel" />
Place navigation components after their carousel in the markup, as above. BlossomDots renders one button per marked slide server-side, before any client JS runs, by reading the slide count that BlossomCarousel registers when it renders. Controls placed before the carousel start at zero dots and fill in on the client.

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 the carousel proportionally.

Slot your own content to replace the default button icon.

<BlossomPrev forId="my-carousel">
  <span>Previous</span>
</BlossomPrev>

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 forId="my-carousel">
  {#snippet children({ index, active })}
    <BlossomDot
      class="my-dot"
      data-active={active}
      aria-label="Photo {index + 1}"
    >
      {index + 1}
    </BlossomDot>
  {/snippet}
</BlossomDots>

Listening for commands

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

  • 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).

<script>
  function handleCommand(event) {
    const command = event?.command || event?.detail?.command;
  }
</script>

<BlossomCarousel oncommand={handleCommand}>
  {#each slides as slide (slide)}
    <div data-blossom-slide>Slide {slide}</div>
  {/each}
</BlossomCarousel>

See the Buttons and Dots examples for live demos.

Overscroll API

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

<script>
  function onOverscroll(event) {
    // prevent and overwrite Blossom's default rubberbanding effect
    event.preventDefault();

    const overScroll = event.detail.left;

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

<BlossomCarousel onoverscroll={onOverscroll}>
  {#each Array.from({ length: 12 }, (_, index) => index + 1) as slide (slide)}
    <div>Slide {slide}</div>
  {/each}
</BlossomCarousel>
BlossomCarousel forwards unrecognized props to its root element, so onoverscroll attaches directly via addEventListener. There's no exposed ref to the root DOM node, so read the target off the event (event.target) rather than binding a ref.