Meet Frontfriend.Your brand. Your rules. Your agents, connected.Explore what’s new
DocumentationCarousel

Carousel

A carousel with motion and swipe built using Embla.

Interactive preview

Rendered from the shared Frontfriend stories with React Base, the same preview Studio shows. Styling comes from your Design System; the code below is native to Reka UI.

Installation

Complete project setup first. Your configuration must select vue/reka and include your Design System ID.

pnpm exec frontfriend download carousel -f vue --primitive reka

Review dependencies reported by the downloader and keep your source changes in version control.

Usage

<script setup lang="ts">
import { Carousel } from "@/components/ui/carousel";
import { CarouselContent } from "@/components/ui/carousel";
import { CarouselItem } from "@/components/ui/carousel";
import { Card } from "@/components/ui/card";
import { CardContent } from "@/components/ui/card";
import { CarouselPrevious } from "@/components/ui/carousel";
import { CarouselNext } from "@/components/ui/carousel";
import * as UI from "@/components/ui/carousel";

const Component = UI.Carousel;

const args = {
  "orientation": "horizontal",
} satisfies Partial<
  InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
  Record<string, unknown> & { orientation?: "horizontal" | "vertical" };
</script>

<template>
  <Carousel class="w-full max-w-xs" v-bind="args"
    ><CarouselContent
      ><CarouselItem v-for="index in 5" :key="index"
        ><div class="p-1">
          <Card
            ><CardContent
              class="flex aspect-square items-center justify-center p-6"
              ><span class="text-4xl font-semibold">{{
                index
              }}</span></CardContent
            ></Card
          >
        </div></CarouselItem
      ></CarouselContent
    ><CarouselPrevious /><CarouselNext
  /></Carousel>
</template>

Examples

Default

<script setup lang="ts">
import { Carousel } from "@/components/ui/carousel";
import { CarouselContent } from "@/components/ui/carousel";
import { CarouselItem } from "@/components/ui/carousel";
import { Card } from "@/components/ui/card";
import { CardContent } from "@/components/ui/card";
import { CarouselPrevious } from "@/components/ui/carousel";
import { CarouselNext } from "@/components/ui/carousel";
import * as UI from "@/components/ui/carousel";

const Component = UI.Carousel;

const args = {

} satisfies Partial<
  InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
  Record<string, unknown>;
</script>

<template>
  <Carousel class="w-full max-w-xs" v-bind="args"
    ><CarouselContent
      ><CarouselItem v-for="index in 5" :key="index"
        ><div class="p-1">
          <Card
            ><CardContent
              class="flex aspect-square items-center justify-center p-6"
              ><span class="text-4xl font-semibold">{{
                index
              }}</span></CardContent
            ></Card
          >
        </div></CarouselItem
      ></CarouselContent
    ><CarouselPrevious /><CarouselNext
  /></Carousel>
</template>

Sizes

<script setup lang="ts">
import { Carousel } from "@/components/ui/carousel";
import { CarouselContent } from "@/components/ui/carousel";
import { CarouselItem } from "@/components/ui/carousel";
import { Card } from "@/components/ui/card";
import { CardContent } from "@/components/ui/card";
import { CarouselPrevious } from "@/components/ui/carousel";
import { CarouselNext } from "@/components/ui/carousel";
import * as UI from "@/components/ui/carousel";

const Component = UI.Carousel;

const args = {

} satisfies Partial<
  InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
  Record<string, unknown>;
</script>

<template>
  <Carousel class="w-full max-w-sm" :opts="{ align: 'start' }"
    ><CarouselContent
      ><CarouselItem
        v-for="index in 5"
        :key="index"
        class="md:basis-1/2 lg:basis-1/3"
        ><div class="p-1">
          <Card
            ><CardContent
              class="flex aspect-square items-center justify-center p-6"
              ><span class="text-3xl font-semibold">{{
                index
              }}</span></CardContent
            ></Card
          >
        </div></CarouselItem
      ></CarouselContent
    ><CarouselPrevious /><CarouselNext
  /></Carousel>
</template>

Spacing

<script setup lang="ts">
import { Carousel } from "@/components/ui/carousel";
import { CarouselContent } from "@/components/ui/carousel";
import { CarouselItem } from "@/components/ui/carousel";
import { Card } from "@/components/ui/card";
import { CardContent } from "@/components/ui/card";
import { CarouselPrevious } from "@/components/ui/carousel";
import { CarouselNext } from "@/components/ui/carousel";
import * as UI from "@/components/ui/carousel";

const Component = UI.Carousel;

const args = {

} satisfies Partial<
  InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
  Record<string, unknown>;
</script>

<template>
  <Carousel class="w-full max-w-sm"
    ><CarouselContent class="-ml-1"
      ><CarouselItem
        v-for="index in 5"
        :key="index"
        class="pl-1 md:basis-1/2 lg:basis-1/3"
        ><div class="p-1">
          <Card
            ><CardContent
              class="flex aspect-square items-center justify-center p-6"
              ><span class="text-2xl font-semibold">{{
                index
              }}</span></CardContent
            ></Card
          >
        </div></CarouselItem
      ></CarouselContent
    ><CarouselPrevious /><CarouselNext
  /></Carousel>
</template>

Orientation

<script setup lang="ts">
import { Carousel } from "@/components/ui/carousel";
import { CarouselContent } from "@/components/ui/carousel";
import { CarouselItem } from "@/components/ui/carousel";
import { Card } from "@/components/ui/card";
import { CardContent } from "@/components/ui/card";
import { CarouselPrevious } from "@/components/ui/carousel";
import { CarouselNext } from "@/components/ui/carousel";
import * as UI from "@/components/ui/carousel";

const Component = UI.Carousel;

const args = {

} satisfies Partial<
  InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
  Record<string, unknown>;
</script>

<template>
  <Carousel
    class="w-full max-w-xs"
    orientation="vertical"
    :opts="{ align: 'start' }"
    ><CarouselContent class="-mt-1 h-[200px]"
      ><CarouselItem v-for="index in 5" :key="index" class="pt-1 md:basis-1/2"
        ><div class="p-1">
          <Card
            ><CardContent class="flex items-center justify-center p-6"
              ><span class="text-3xl font-semibold">{{
                index
              }}</span></CardContent
            ></Card
          >
        </div></CarouselItem
      ></CarouselContent
    ><CarouselPrevious /><CarouselNext
  /></Carousel>
</template>

Api

<script setup lang="ts">
import { ref } from "vue";
import * as UI from "@/components/ui/carousel";
import { watch } from "vue";
import { Carousel } from "@/components/ui/carousel";
import { CarouselContent } from "@/components/ui/carousel";
import { CarouselItem } from "@/components/ui/carousel";
import { Card } from "@/components/ui/card";
import { CardContent } from "@/components/ui/card";
import { CarouselPrevious } from "@/components/ui/carousel";
import { CarouselNext } from "@/components/ui/carousel";

const Component = UI.Carousel;

const args = {

} satisfies Partial<
  InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
  Record<string, unknown>;
const api = ref<UI.CarouselApi>();
const current = ref(0);
const count = ref(0);
function setApi(val: UI.CarouselApi) {
  api.value = val;
}
watch(api, (value) => {
  if (!value) return;
  count.value = value.scrollSnapList().length;
  current.value = value.selectedScrollSnap() + 1;
  value.on("select", () => {
    current.value = value.selectedScrollSnap() + 1;
  });
});
</script>

<template>
  <div class="mx-auto max-w-xs">
    <Carousel class="w-full max-w-xs" @init-api="setApi"
      ><CarouselContent
        ><CarouselItem v-for="index in 5" :key="index"
          ><div class="p-1">
            <Card
              ><CardContent
                class="flex aspect-square items-center justify-center p-6"
                ><span class="text-4xl font-semibold">{{
                  index
                }}</span></CardContent
              ></Card
            >
          </div></CarouselItem
        ></CarouselContent
      ><CarouselPrevious /><CarouselNext
    /></Carousel>
    <div class="py-2 text-center text-sm text-neutral-mid">
      Slide {{ current }} of {{ count }}
    </div>
  </div>
</template>

API reference

Frontfriend-owned props. Native HTML and inherited primitive props remain documented by Reka UI.

CarouselNext

Prop Type Default Description
size ButtonVariants["size"] —
variant ButtonVariants["variant"] —

CarouselPrevious

Prop Type Default Description
size ButtonVariants["size"] —
variant ButtonVariants["variant"] —

Configuration determines the actual classes and available styling hooks. See Theming & component configuration before introducing a repeated local override.