Carousel
A carousel with motion and swipe built using Embla.
About
The carousel component is built using the Embla Carousel library.
Installation
npx nyxbui@latest add carousel
Usage
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "~/components/ui/carousel"
<Carousel>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
Examples
Sizes
To set the size of the items, you can use the basis
utility class on the <CarouselItem />
.
// 33% of the carousel width.
<Carousel>
<CarouselContent>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
// 50% on small screens and 33% on larger screens.
<Carousel>
<CarouselContent>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
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 />
.
Why: I tried to use the gap
property or a grid
layout on the <CarouselContent />
but it required a lot of math and mental effort to get the
spacing right. I found pl-[VALUE]
and -ml-[VALUE]
utilities much easier to
use.
You can always adjust this in your own project if you need to.
<Carousel>
<CarouselContent className="-ml-4">
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
<Carousel>
<CarouselContent className="-ml-2 md:-ml-4">
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
Orientation
Use the orientation
prop to set the orientation of the carousel.
<Carousel orientation="vertical | horizontal">
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
Dots
Enhance carousel navigation with the CarouselDots component, which presents interactive indicators for each slide.
Usage
Embed within the Carousel, connecting automatically to its context for slide information and active index.
dotsPosition
: Dots placement - "top", "bottom", "left", or "right".size
: Size of Dot - "default", "sm", "md", "lg".gap
: Space between dots - "default", "sm", "md", "lg".
<Carousel
orientation="vertical | horizontal"
dotsPosition="top | bottom | left | right"
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
...
</CarouselContent>
<CarouselDots size="sm | md | lg" gap="sm | md | lg" />
...
</Carousel>
Options
You can pass options to the carousel using the opts
prop. See the Embla Carousel docs for more information.
<Carousel
opts={{
align: "start",
loop: true,
}}
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
API
Use a state and the setApi
props to get an instance of the carousel API.
import { type CarouselApi } from "~/components/ui/carousel"
export function Example() {
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 (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
)
}
Events
You can listen to events using the api instance from setApi
.
import { type CarouselApi } from "~/components/ui/carousel"
export function Example() {
const [api, setApi] = React.useState<CarouselApi>()
React.useEffect(() => {
if (!api) {
return
}
api.on("select", () => {
// Do something on select.
})
}, [api])
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
)
}
See the Embla Carousel docs for more information on using events.
Plugins
You can use the plugins
prop to add plugins to the carousel.
import Autoplay from "embla-carousel-autoplay"
export function Example() {
return (
<Carousel
plugins={[
Autoplay({
delay: 2000,
}),
]}
>
// ...
</Carousel>
)
}
See the Embla Carousel docs for more information on using plugins.