Componentmedia
Carousel
Sliding track carousel with prev/next arrows, dot indicators, keyboard arrows, and optional autoplay.
Preview
Live Preview
Summer Sale
Get 20% off on all items. Use code SUMMER20 at checkout.
New Arrivals
Check out our latest collection arriving this week.
Clearance
Last chance to buy at these prices.
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add carouselOr install the full npm package:
npm install bigbulluiUsage
import { Carousel } from "@/components/ui/carousel";
<Carousel items={slides} autoplay interval={5000} />Source code
carousel.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export type CarouselItem = {
title: string;
description: string;
children: React.ReactNode;
};
export type CarouselSlide = {
title: string;
description: string;
};
export type CarouselProps = {
items: CarouselItem[];
autoplay?: boolean;
interval?: number;
className?: string;
};
const Carousel = React.forwardRef<
HTMLDivElement,
CarouselProps
>(({ items, autoplay = false, interval = 3000, className }, ref) => {
const [activeIndex, setActiveIndex] = React.useState(0);
React.useEffect(() => {
if (!autoplay) return;
const id = setInterval(() => {
setActiveIndex((i) => (i + 1) % items.length);
}, interval);
return () => clearInterval(id);
}, [autoplay, interval, items.length]);
const prev = () => setActiveIndex((i) => (i - 1 + items.length) % items.length);
const next = () => setActiveIndex((i) => (i + 1) % items.length);
return (
<div
ref={ref}
className={cn(
"relative overflow-hidden rounded-lg bg-card p-2",
"motion-reduce:animate-none",
className
)}
>
<div
className={cn(
"relative flex transition-transform duration-500 ease-out",
"motion-reduce:transition-none"
)}
style={{ transform: `translateX(${-activeIndex * 100}%)` }}
>
{items.map((item, index) => (
<div
key={item.title}
className={cn(
"relative flex flex-col items-center justify-center py-8 px-2 shrink-0",
"motion-reduce:animate-none"
)}
>
<h3 className="text-xl font-semibold text-foreground mb-1">{item.title}</h3>
<p className="text-sm text-muted-foreground">{item.description}</p>
</div>
))}
</div>
<div
className={cn(
"absolute top-0 left-0 right-0 flex justify-between p-2",
"motion-reduce:animate-none"
)}
>
<button
onClick={prev}
className={cn(
"absolute left-2 rounded-md p-1.5 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"motion-reduce:transition-none"
)}
aria-label="Previous"
>
{"<"}
</button>
<button
onClick={next}
className={cn(
"absolute right-2 rounded-md p-1.5 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"motion-reduce:transition-none"
)}
aria-label="Next"
>
{">"}
</button>
</div>
</div>
);
});
Carousel.displayName = "Carousel";
export { Carousel };
Props
| Prop | Type | Description |
|---|---|---|
| items | CarouselItem[] | Slides to render. |
| autoplay | boolean | Advance automatically. |
| interval | number | Autoplay delay in ms (default 3000). |