Carousel
A carousel with motion and swipe built using Embla.
import { For } from "solid-js";
import { Card, CardContent } from "~/components/ui/card";import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from "~/components/ui/carousel";
export default function CarouselDemo() { return ( <Carousel aria-label="Carousel demo" class="w-full max-w-[12rem] sm:max-w-xs"> <CarouselContent> <For each={Array.from({ length: 5 })}> {(_, index) => ( <CarouselItem> <div class="p-1"> <Card> <CardContent class="flex aspect-square items-center justify-center p-6"> <span class="text-4xl font-semibold">{index() + 1}</span> </CardContent> </Card> </div> </CarouselItem> )} </For> </CarouselContent> <CarouselPrevious /> <CarouselNext /> </Carousel> );}About
The Carousel component is built with Embla Carousel, which provides motion, swipe, and keyboard navigation.
Installation
Usage
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from "~/components/ui/carousel";<Carousel> <CarouselContent> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> </CarouselContent> <CarouselPrevious /> <CarouselNext /></Carousel>Composition
Use the following composition to build a Carousel:
Carousel├── CarouselContent│ ├── CarouselItem│ └── CarouselItem├── CarouselPrevious└── CarouselNextSizes
To set the size of the items, use the basis utility class on <CarouselItem />.
import { For } from "solid-js";
import { Card, CardContent } from "~/components/ui/card";import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from "~/components/ui/carousel";
export default function CarouselSize() { return ( <Carousel aria-label="Carousel size example" opts={{ align: "start" }} class="w-full max-w-[12rem] sm:max-w-xs md:max-w-sm" > <CarouselContent> <For each={Array.from({ length: 5 })}> {(_, index) => ( <CarouselItem class="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() + 1}</span> </CardContent> </Card> </div> </CarouselItem> )} </For> </CarouselContent> <CarouselPrevious /> <CarouselNext /> </Carousel> );}// 33% of the carousel width.<Carousel> <CarouselContent> <CarouselItem class="basis-1/3">...</CarouselItem> <CarouselItem class="basis-1/3">...</CarouselItem> <CarouselItem class="basis-1/3">...</CarouselItem> </CarouselContent></Carousel>// 50% on small screens and 33% on larger screens.<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>Spacing
To set item spacing, use a pl-[VALUE] utility on <CarouselItem /> and a negative -ml-[VALUE] on <CarouselContent />.
import { For } from "solid-js";
import { Card, CardContent } from "~/components/ui/card";import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from "~/components/ui/carousel";
export default function CarouselSpacing() { return ( <Carousel aria-label="Carousel spacing example" class="w-full max-w-[12rem] sm:max-w-xs md:max-w-sm" > <CarouselContent class="-ml-1"> <For each={Array.from({ length: 5 })}> {(_, index) => ( <CarouselItem class="basis-1/2 pl-1 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() + 1}</span> </CardContent> </Card> </div> </CarouselItem> )} </For> </CarouselContent> <CarouselPrevious /> <CarouselNext /> </Carousel> );}<Carousel> <CarouselContent class="-ml-4"> <CarouselItem class="pl-4">...</CarouselItem> <CarouselItem class="pl-4">...</CarouselItem> <CarouselItem class="pl-4">...</CarouselItem> </CarouselContent></Carousel><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>Orientation
Use the orientation prop to set the carousel orientation.
import { For } from "solid-js";
import { Card, CardContent } from "~/components/ui/card";import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from "~/components/ui/carousel";
export default function CarouselOrientation() { return ( <Carousel aria-label="Vertical carousel example" opts={{ align: "start" }} orientation="vertical" class="w-full max-w-xs" > <CarouselContent class="-mt-1 h-[270px]"> <For each={Array.from({ length: 5 })}> {(_, index) => ( <CarouselItem class="basis-1/2 pt-1"> <div class="p-1"> <Card> <CardContent class="flex items-center justify-center p-6"> <span class="text-3xl font-semibold">{index() + 1}</span> </CardContent> </Card> </div> </CarouselItem> )} </For> </CarouselContent> <CarouselPrevious /> <CarouselNext /> </Carousel> );}<Carousel orientation="vertical | horizontal"> <CarouselContent> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> </CarouselContent></Carousel>Options
Pass options to the carousel using the opts prop. See the Embla Carousel options documentation for more information.
<Carousel opts={{ align: "start", loop: true, }}> <CarouselContent> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> </CarouselContent></Carousel>API
Use a signal and the setApi prop to get an instance of the carousel API.
import { createEffect, createSignal, For, onCleanup } from "solid-js";
import { Card, CardContent } from "~/components/ui/card";import { Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from "~/components/ui/carousel";
export default function CarouselApiDemo() { const [api, setApi] = createSignal<CarouselApi>(); const [current, setCurrent] = createSignal(0); const [count, setCount] = createSignal(0);
createEffect(() => { const carouselApi = api(); if (!carouselApi) return;
const onSelect = () => setCurrent(carouselApi.selectedScrollSnap() + 1);
setCount(carouselApi.scrollSnapList().length); onSelect(); carouselApi.on("select", onSelect); onCleanup(() => carouselApi.off("select", onSelect)); });
return ( <div class="mx-auto max-w-[10rem] sm:max-w-xs"> <Carousel aria-label="Carousel API example" setApi={setApi} class="w-full max-w-xs"> <CarouselContent> <For each={Array.from({ length: 5 })}> {(_, index) => ( <CarouselItem> <Card class="m-px"> <CardContent class="flex aspect-square items-center justify-center p-6"> <span class="text-4xl font-semibold">{index() + 1}</span> </CardContent> </Card> </CarouselItem> )} </For> </CarouselContent> <CarouselPrevious /> <CarouselNext /> </Carousel> <div class="py-2 text-center text-sm text-muted-foreground"> Slide {current()} of {count()} </div> </div> );}import { createEffect, createSignal, onCleanup } from "solid-js";import { type CarouselApi } from "~/components/ui/carousel";
export function Example() { const [api, setApi] = createSignal<CarouselApi>(); const [current, setCurrent] = createSignal(0); const [count, setCount] = createSignal(0);
createEffect(() => { const carouselApi = api(); if (!carouselApi) return;
const onSelect = () => { setCurrent(carouselApi.selectedScrollSnap() + 1); };
setCount(carouselApi.scrollSnapList().length); onSelect(); carouselApi.on("select", onSelect); onCleanup(() => carouselApi.off("select", onSelect)); });
return ( <Carousel setApi={setApi}> <CarouselContent> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> </CarouselContent> </Carousel> );}Events
Listen to events using the API instance from setApi.
import { createEffect, createSignal, onCleanup } from "solid-js";import { type CarouselApi } from "~/components/ui/carousel";
export function Example() { const [api, setApi] = createSignal<CarouselApi>();
createEffect(() => { const carouselApi = api(); if (!carouselApi) return;
const onSelect = () => { // Do something on select. };
carouselApi.on("select", onSelect); onCleanup(() => carouselApi.off("select", onSelect)); });
return ( <Carousel setApi={setApi}> <CarouselContent> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> <CarouselItem>...</CarouselItem> </CarouselContent> </Carousel> );}See the Embla Carousel events documentation for more information.
Plugins
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> );}import Autoplay from "embla-carousel-autoplay";import { For } from "solid-js";
import { Card, CardContent } from "~/components/ui/card";import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from "~/components/ui/carousel";
export default function CarouselPlugin() { const plugin = Autoplay({ delay: 2000, stopOnInteraction: true });
return ( <Carousel aria-label="Carousel autoplay example" plugins={[plugin]} class="w-full max-w-[10rem] sm:max-w-xs" onMouseEnter={plugin.stop} onMouseLeave={plugin.reset} > <CarouselContent> <For each={Array.from({ length: 5 })}> {(_, index) => ( <CarouselItem> <div class="p-1"> <Card> <CardContent class="flex aspect-square items-center justify-center p-6"> <span class="text-4xl font-semibold">{index() + 1}</span> </CardContent> </Card> </div> </CarouselItem> )} </For> </CarouselContent> <CarouselPrevious /> <CarouselNext /> </Carousel> );}API Reference
See the Embla Carousel API reference for information on options, events, and plugins.