Carousel
optics/carouselFreeComponent
A carousel with motion and swipe built using Embla.
See it running
Open the demo on optics
optics.agusmayol.com.ar/components/carouselInstall it
npx shadcn@latest add https://optics.agusmayol.com.ar/r/carousel.jsonSource
1"use client";2import * as React from "react";3import useEmblaCarousel from "embla-carousel-react";45import { cn } from "@/lib/utils";6import { Button } from "@/registry/optics/button";7import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";89const CarouselContext = React.createContext(null);1011function useCarousel() {12 const context = React.useContext(CarouselContext);1314 if (!context) {15 throw new Error("useCarousel must be used within a <Carousel />");16 }1718 return context;19}2021function Carousel({22 orientation = "horizontal",23 opts = {},24 setApi = undefined,25 plugins = [],26 className = "",27 children = null,28 ...props29}) {30 const [carouselRef, api] = useEmblaCarousel(31 {32 ...opts,33 axis: orientation === "horizontal" ? "x" : "y",34 },35 plugins,36 );37 const [canScrollPrev, setCanScrollPrev] = React.useState(false);38 const [canScrollNext, setCanScrollNext] = React.useState(false);3940 const onSelect = React.useCallback((api) => {41 if (!api) return;42 setCanScrollPrev(api.canScrollPrev());43 setCanScrollNext(api.canScrollNext());44 }, []);4546 const scrollPrev = React.useCallback(() => {47 api?.scrollPrev();48 }, [api]);4950 const scrollNext = React.useCallback(() => {51 api?.scrollNext();52 }, [api]);5354 const handleKeyDown = React.useCallback(55 (event) => {56 if (event.key === "ArrowLeft") {57 event.preventDefault();58 scrollPrev();59 } else if (event.key === "ArrowRight") {60 event.preventDefault();61 scrollNext();62 }63 },64 [scrollPrev, scrollNext],65 );6667 React.useEffect(() => {68 if (!api || !setApi) return;69 setApi(api);70 }, [api, setApi]);7172 React.useEffect(() => {73 if (!api) return;74 onSelect(api);75 api.on("reInit", onSelect);76 api.on("select", onSelect);7778 return () => {79 api?.off("select", onSelect);80 };81 }, [api, onSelect]);8283 return (84 <CarouselContext.Provider85 value={{86 carouselRef,87 api: api,88 opts,89 orientation:90 orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),91 scrollPrev,92 scrollNext,93 canScrollPrev,94 canScrollNext,95 }}96 >97 <div98 onKeyDownCapture={handleKeyDown}99 className={cn("relative", className)}100 role="region"101 aria-roledescription="carousel"102 data-slot="carousel"103 {...props}104 >105 {children}106 </div>107 </CarouselContext.Provider>108 );109}110111function CarouselContent({ className = "", ...props }) {112 const { carouselRef, orientation } = useCarousel();113114 return (115 <div116 ref={carouselRef}117 className="overflow-hidden"118// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from optics
All 79 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | optics | Components | Free | 5 deps | |
| Alertalert | optics | Components | Free | 4 deps | |
| Alert Dialogalert-dialog | optics | Components | Free | 4 deps | |
| Aspect Ratioaspect-ratio | optics | Components | Free | 2 deps | |
| Auto Heightauto-height | optics | Components | Free | 3 deps | |
| Avataravatar | optics | Components | Free | 3 deps | |
| Badgebadge | optics | Components | Free | 4 deps | |
| Breadcrumbbreadcrumb | optics | Components | Free | 4 deps |
