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 Base UI.

Installation

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

pnpm exec frontfriend download carousel -f react --primitive base

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

Usage

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
function Slide({ value, square = true }: { value: number; square?: boolean }) {
  return (
    <div className="p-1">
      <Card>
        <CardContent
          className={`flex items-center justify-center p-6${square ? " aspect-square" : ""}`}
        >
          <span className="text-3xl font-semibold">{value}</span>
        </CardContent>
      </Card>
    </div>
  );
}
<Carousel className="w-full max-w-xs" orientation="horizontal">
  <CarouselContent>
    {Array.from({ length: 5 }).map((_, index) => (
      <CarouselItem key={index}>
        <Slide value={index + 1} />
      </CarouselItem>
    ))}
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>;

Examples

Default

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
function Slide({ value, square = true }: { value: number; square?: boolean }) {
  return (
    <div className="p-1">
      <Card>
        <CardContent
          className={`flex items-center justify-center p-6${square ? " aspect-square" : ""}`}
        >
          <span className="text-3xl font-semibold">{value}</span>
        </CardContent>
      </Card>
    </div>
  );
}
<Carousel className="w-full max-w-xs" >
  <CarouselContent>
    {Array.from({ length: 5 }).map((_, index) => (
      <CarouselItem key={index}>
        <Slide value={index + 1} />
      </CarouselItem>
    ))}
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>;

Sizes

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
function Slide({ value, square = true }: { value: number; square?: boolean }) {
  return (
    <div className="p-1">
      <Card>
        <CardContent
          className={`flex items-center justify-center p-6${square ? " aspect-square" : ""}`}
        >
          <span className="text-3xl font-semibold">{value}</span>
        </CardContent>
      </Card>
    </div>
  );
}
<Carousel opts={{ align: "start" }} className="w-full max-w-sm">
  <CarouselContent>
    {Array.from({ length: 5 }).map((_, index) => (
      <CarouselItem key={index} className="md:basis-1/2 lg:basis-1/3">
        <Slide value={index + 1} />
      </CarouselItem>
    ))}
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>;

Spacing

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
function Slide({ value, square = true }: { value: number; square?: boolean }) {
  return (
    <div className="p-1">
      <Card>
        <CardContent
          className={`flex items-center justify-center p-6${square ? " aspect-square" : ""}`}
        >
          <span className="text-3xl font-semibold">{value}</span>
        </CardContent>
      </Card>
    </div>
  );
}
<Carousel className="w-full max-w-sm">
  <CarouselContent className="-ml-1">
    {Array.from({ length: 5 }).map((_, index) => (
      <CarouselItem key={index} className="pl-1 md:basis-1/2 lg:basis-1/3">
        <Slide value={index + 1} />
      </CarouselItem>
    ))}
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>;

Orientation

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
function Slide({ value, square = true }: { value: number; square?: boolean }) {
  return (
    <div className="p-1">
      <Card>
        <CardContent
          className={`flex items-center justify-center p-6${square ? " aspect-square" : ""}`}
        >
          <span className="text-3xl font-semibold">{value}</span>
        </CardContent>
      </Card>
    </div>
  );
}
<Carousel
  opts={{ align: "start" }}
  orientation="vertical"
  className="w-full max-w-xs"
>
  <CarouselContent className="-mt-1 h-[200px]">
    {Array.from({ length: 5 }).map((_, index) => (
      <CarouselItem key={index} className="pt-1 md:basis-1/2">
        <Slide value={index + 1} square={false} />
      </CarouselItem>
    ))}
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>;

Api

import {
  CarouselApi,
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
import * as React from "react";
function Slide({ value, square = true }: { value: number; square?: boolean }) {
  return (
    <div className="p-1">
      <Card>
        <CardContent
          className={`flex items-center justify-center p-6${square ? " aspect-square" : ""}`}
        >
          <span className="text-3xl font-semibold">{value}</span>
        </CardContent>
      </Card>
    </div>
  );
}
export default function CarouselExample() {
  const [api, setApi] = React.useState<CarouselApi>();
  const [current, setCurrent] = React.useState(0);
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    if (!api) return;
    setCount(api.scrollSnapList().length);
    setCurrent(api.selectedScrollSnap() + 1);
    api.on("select", () => setCurrent(api.selectedScrollSnap() + 1));
  }, [api]);
  return (
    <div className="mx-auto max-w-xs">
      <Carousel setApi={setApi} className="w-full max-w-xs">
        <CarouselContent>
          {Array.from({ length: 5 }).map((_, index) => (
            <CarouselItem key={index}>
              <Slide value={index + 1} />
            </CarouselItem>
          ))}
        </CarouselContent>
        <CarouselPrevious />
        <CarouselNext />
      </Carousel>
      <div className="py-2 text-center text-sm text-neutral-mid">
        Slide {current} of {count}
      </div>
    </div>
  );
}

API reference

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

Prop Type Default Description
opts CarouselOptions —
orientation "horizontal" | "vertical" "horizontal" Set the orientation of the carousel.
plugins CarouselPlugin —
setApi (api: CarouselApi) => void —

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