Carousel

The carousel component provides a way to display a series of images or videos.

WAI-ARIA: Carousel Pattern

Features

Automatic pause

The carousel will automatically pause when the user is interacting with it. This includes when the user is hovering over the carousel, or when the user is interacting with the carousel via the keyboard.

Also, if the user prefers reduced motion, the carousel will not automatically advance.

Example

Sources

+page.svelte

<script lang="ts">
  import Carousel from './Carousel.svelte'
  import Slide from './Slide.svelte'
</script>

<Carousel>
  <Slide>
    <img src="https://picsum.photos/seed/1/800/300" alt />
  </Slide>
  <Slide>
    <img src="https://picsum.photos/seed/2/800/300" alt />
  </Slide>
  <Slide>
    <img src="https://picsum.photos/seed/3/800/300" alt />
  </Slide>
</Carousel>

Carousel.svelte

<script lang="ts">
  import { createCarousel } from 'louisette'
  import { setContext } from 'svelte'

  export let controls = true

  const {
    carouselAttrs,
    trackAttrs,
    previousButtonAttrs,
    nextButtonAttrs,
    status,
    ...carouselContext
  } = createCarousel({
    autoplay: true,
    loop: true,
    interval: 2000,
  })

  setContext('carousel', carouselContext)
</script>

<div {...$carouselAttrs} class="relative flex flex-col">
  <div {...$trackAttrs} class="flex flex-row">
    <slot />
  </div>
  {#if controls}
    <button
      {...$previousButtonAttrs}
      class="absolute left-2 top-1/2 -translate-y-1/2 transform rounded-full bg-white text-neutral-950 shadow hover:bg-neutral-300 dark:bg-neutral-900 dark:text-white dark:hover:bg-neutral-800"
    >
      <svg class="h-6 w-6 md:h-10 md:w-10" viewBox="0 0 24 24">
        <path
          fill="currentColor"
          d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"
        />
      </svg>
    </button>
    <button
      {...$nextButtonAttrs}
      class="absolute right-2 top-1/2 -translate-y-1/2 transform rounded-full bg-white text-neutral-950 shadow hover:bg-neutral-300 dark:bg-neutral-900 dark:text-white dark:hover:bg-neutral-800"
    >
      <svg class="h-6 w-6 md:h-10 md:w-10" viewBox="0 0 24 24">
        <path
          fill="currentColor"
          d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"
        />
      </svg>
    </button>
  {/if}
  <div
    class="absolute bottom-2 left-2 inline-block rounded bg-white px-2 py-1 text-xs text-neutral-950 shadow dark:bg-neutral-900 dark:text-white"
    aria-hidden="true"
  >
    {$status}
  </div>
</div>

Slide.svelte

<script lang="ts">
  import { createKey, type Carousel } from 'louisette'
  import { getContext } from 'svelte'

  const key = createKey()

  const { slideAttrs, current } = getContext<Carousel>('carousel')
</script>

<div {...$slideAttrs(key)} class="slide w-full" class:hidden={key !== $current}>
  <slot />
</div>

<style lang="postcss">
  .slide :global(img) {
    @apply h-full w-full rounded object-cover;
  }
</style>