120k

Carousel

A carousel with motion and swipe built using Embla.

About

The carousel component is built using the Embla Carousel library.

Installation

pnpm dlx shadcn@latest add @force-ui-vue/carousel

Usage

<script setup lang="ts">
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from "@/components/ui/carousel"
</script>
 
<template>
  <Carousel>
    <CarouselContent>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
  </Carousel>
</template>

Composition

Use the following composition to build a Carousel:

Carousel
├── CarouselContent
│   ├── CarouselItem
│   └── CarouselItem
├── CarouselPrevious
└── CarouselNext

Examples

Sizes

To set the size of the items, you can use the basis utility class on the <CarouselItem />.

// 33% of the carousel width.
<template>
  <Carousel>
    <CarouselContent>
      <CarouselItem class="basis-1/3"> ... </CarouselItem>
      <CarouselItem class="basis-1/3"> ... </CarouselItem>
      <CarouselItem class="basis-1/3"> ... </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>
// 50% on small screens and 33% on larger screens.
<template>
  <Carousel>
    <CarouselContent>
      <CarouselItem class="md:basis-1/2 lg:basis-1/3"> ... </CarouselItem>
      <CarouselItem class="md:basis-1/2 lg:basis-1/3"> ... </CarouselItem>
      <CarouselItem class="md:basis-1/2 lg:basis-1/3"> ... </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>

Spacing

To set the spacing between the items, we use a pl-[VALUE] utility on the <CarouselItem /> and a negative -ml-[VALUE] on the <CarouselContent />.

<template>
  <Carousel>
    <CarouselContent class="-ml-4">
      <CarouselItem class="pl-4"> ... </CarouselItem>
      <CarouselItem class="pl-4"> ... </CarouselItem>
      <CarouselItem class="pl-4"> ... </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>
<template>
  <Carousel>
    <CarouselContent class="-ml-2 md:-ml-4">
      <CarouselItem class="pl-2 md:pl-4"> ... </CarouselItem>
      <CarouselItem class="pl-2 md:pl-4"> ... </CarouselItem>
      <CarouselItem class="pl-2 md:pl-4"> ... </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>

Orientation

Use the orientation prop to set the orientation of the carousel.

<Carousel orientation="vertical | horizontal">
  ...
</Carousel>

Options

You can pass options to the carousel using the opts prop. See the Embla Carousel docs for more information.

<template>
  <Carousel
    :opts="{
      align: 'start',
      loop: true,
    }"
  >
    <CarouselContent>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
    </CarouselContent>
  </Carousel>
</template>

API

Method 1

Use the @init-api emit method on <Carousel /> component to set the instance of the API.

Method 2

You can access it through setting a template ref on the <Carousel /> component.

<script setup lang="ts">
const carouselContainerRef = ref<InstanceType<typeof Carousel> | null>(null)
 
function accessApi() {
  carouselContainerRef.value?.carouselApi.on("select", () => {})
}
</script>
 
<template>
  <Carousel ref="carouselContainerRef"> ... </Carousel>
</template>

Events

You can listen to events using the API. To get the API instance use the @init-api emit method on the <Carousel /> component

<script setup lang="ts">
import { nextTick, ref, watch } from "vue"
 
import { useCarousel } from "@/components/ui/carousel"
 
const api = ref<CarouselApi>()
 
function setApi(val: CarouselApi) {
  api.value = val
}
 
const stop = watch(api, (api) => {
  if (!api) return
 
  // Watch only once or use watchOnce() in @vueuse/core
  nextTick(() => stop())
 
  api.on("select", () => {
    // Do something on select.
  })
})
</script>
 
<template>
  <Carousel @init-api="setApi"> ... </Carousel>
</template>

See the Embla Carousel docs for more information on using events.

Plugins

You can use the plugins prop to add plugins to the carousel.

pnpm add embla-carousel-autoplay
<script setup lang="ts">
import Autoplay from "embla-carousel-autoplay"
</script>
 
<template>
  <Carousel
    class="w-full max-w-xs"
    :plugins="[
      Autoplay({
        delay: 2000,
      }),
    ]"
  >
    ...
  </Carousel>
</template>

See the Embla Carousel docs for more information on using plugins.

RTL

To enable RTL support in Force UI, see the RTL configuration guide.

When localizing the carousel for RTL languages, you need to set the direction option in the :opts prop to match the text direction. This ensures the carousel scrolls in the correct direction.

<template>
  <Carousel
    :dir="dir"
    :opts="{
      direction: dir,
    }"
  >
    <CarouselContent>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
    </CarouselContent>
    <CarouselPrevious class="rtl:rotate-180" />
    <CarouselNext class="rtl:rotate-180" />
  </Carousel>
</template>

The direction option accepts "ltr" or "rtl" and should match the :dir prop value. You may also want to rotate the navigation buttons using the rtl:rotate-180 class to ensure they point in the correct direction.

Slot Props

You can get the reactive slot props like carouselRef, canScrollNext..Prev, scrollNext..Prev using the v-slot directive in the <Carousel v-slot="slotProps" /> component to extend the functionality.

<template>
  <Carousel v-slot="{ canScrollNext, canScrollPrev }">
    ...
    <CarouselPrevious v-if="canScrollPrev" />
    <CarouselNext v-if="canScrollNext" />
  </Carousel>
</template>

API Reference

See the Embla Carousel docs for more information on props and plugins.