Carousel
basecn/carouselFreeComponent
A carousel with motion and swipe built using Embla.
Live preview
live · rendered by the registry
Rendered by basecn on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://basecn.dev/r/carousel.jsonSource
1"use client";23import * as React from "react";4import useEmblaCarousel, {5 type UseEmblaCarouselType,6} from "embla-carousel-react";7import { ArrowLeft, ArrowRight } from "lucide-react";89import { cn } from "@/lib/utils";10import { Button } from "@/registry/components/ui/button";1112type CarouselApi = UseEmblaCarouselType[1];13type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;14type CarouselOptions = UseCarouselParameters[0];15type CarouselPlugin = UseCarouselParameters[1];1617type CarouselProps = {18 opts?: CarouselOptions;19 plugins?: CarouselPlugin;20 orientation?: "horizontal" | "vertical";21 setApi?: (api: CarouselApi) => void;22};2324type CarouselContextProps = {25 carouselRef: ReturnType<typeof useEmblaCarousel>[0];26 api: ReturnType<typeof useEmblaCarousel>[1];27 scrollPrev: () => void;28 scrollNext: () => void;29 canScrollPrev: boolean;30 canScrollNext: boolean;31} & CarouselProps;3233const CarouselContext = React.createContext<CarouselContextProps | null>(null);3435function useCarousel() {36 const context = React.useContext(CarouselContext);3738 if (!context) {39 throw new Error("useCarousel must be used within a <Carousel />");40 }4142 return context;43}4445function Carousel({46 orientation = "horizontal",47 opts,48 setApi,49 plugins,50 className,51 children,52 ...props53}: React.ComponentProps<"div"> & CarouselProps) {54 const [carouselRef, api] = useEmblaCarousel(55 {56 ...opts,57 axis: orientation === "horizontal" ? "x" : "y",58 },59 plugins60 );61 const [canScrollPrev, setCanScrollPrev] = React.useState(false);62 const [canScrollNext, setCanScrollNext] = React.useState(false);6364 const onSelect = React.useCallback((api: CarouselApi) => {65 if (!api) return;66 setCanScrollPrev(api.canScrollPrev());67 setCanScrollNext(api.canScrollNext());68 }, []);6970 const scrollPrev = React.useCallback(() => {71 api?.scrollPrev();72 }, [api]);7374 const scrollNext = React.useCallback(() => {75 api?.scrollNext();76 }, [api]);7778 const handleKeyDown = React.useCallback(79 (event: React.KeyboardEvent<HTMLDivElement>) => {80 if (event.key === "ArrowLeft") {81 event.preventDefault();82 scrollPrev();83 } else if (event.key === "ArrowRight") {84 event.preventDefault();85 scrollNext();86 }87 },88 [scrollPrev, scrollNext]89 );9091 React.useEffect(() => {92 if (!api || !setApi) return;93 setApi(api);94 }, [api, setApi]);9596 React.useEffect(() => {97 if (!api) return;98 onSelect(api);99// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from basecn
All 56 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | basecn | Components | Free | 2 deps | |
| Alertalert | basecn | Components | Free | 1 dep | |
| Alert Dialogalert-dialog | basecn | Components | Free | 1 dep | |
| Aspect Ratioaspect-ratio | basecn | Components | Free | no deps | |
| Autocompleteautocomplete | basecn | Components | Free | 2 deps | |
| Avataravatar | basecn | Components | Free | 1 dep | |
| Badgebadge | basecn | Components | Free | 2 deps | |
| Breadcrumbbreadcrumb | basecn | Components | Free | 2 deps |
