Motion Carousel
animate-ui/components-community-motion-carouselFreeComponent
A carousel built on top of Embla Carousel with smooth Motion-powered animations. Each slide scales dynamically based on its active state, and the pagination uses animated pill-style dot buttons for an interactive, fluid experience.
Install it
npx shadcn@latest add https://animate-ui.com/r/components-community-motion-carousel.jsonSource
1'use client';23import * as React from 'react';4import { motion, type Transition } from 'motion/react';5import { EmblaOptionsType, EmblaCarouselType } from 'embla-carousel';6import useEmblaCarousel from 'embla-carousel-react';7import { Button } from '@/components/animate-ui/components/buttons/button';8import { ChevronRight, ChevronLeft } from 'lucide-react';910type PropType = {11 slides: number[];12 options?: EmblaOptionsType;13};1415type EmblaControls = {16 selectedIndex: number;17 scrollSnaps: number[];18 prevDisabled: boolean;19 nextDisabled: boolean;20 onDotClick: (index: number) => void;21 onPrev: () => void;22 onNext: () => void;23};2425type DotButtonProps = {26 selected?: boolean;27 label: string;28 onClick: () => void;29};3031const transition: Transition = {32 type: 'spring',33 stiffness: 240,34 damping: 24,35 mass: 1,36};3738const useEmblaControls = (39 emblaApi: EmblaCarouselType | undefined,40): EmblaControls => {41 const [selectedIndex, setSelectedIndex] = React.useState(0);42 const [scrollSnaps, setScrollSnaps] = React.useState<number[]>([]);43 const [prevDisabled, setPrevDisabled] = React.useState(true);44 const [nextDisabled, setNextDisabled] = React.useState(true);4546 const onDotClick = React.useCallback(47 (index: number) => emblaApi?.scrollTo(index),48 [emblaApi],49 );5051 const onPrev = React.useCallback(() => emblaApi?.scrollPrev(), [emblaApi]);52 const onNext = React.useCallback(() => emblaApi?.scrollNext(), [emblaApi]);5354 const updateSelectionState = (api: EmblaCarouselType) => {55 setSelectedIndex(api.selectedScrollSnap());56 setPrevDisabled(!api.canScrollPrev());57 setNextDisabled(!api.canScrollNext());58 };5960 const onInit = React.useCallback((api: EmblaCarouselType) => {61 setScrollSnaps(api.scrollSnapList());62 updateSelectionState(api);63 }, []);6465 const onSelect = React.useCallback((api: EmblaCarouselType) => {66 updateSelectionState(api);67 }, []);6869 React.useEffect(() => {70 if (!emblaApi) return;7172 onInit(emblaApi);73 emblaApi.on('reInit', onInit).on('select', onSelect);7475 return () => {76 emblaApi.off('reInit', onInit).off('select', onSelect);77 };78 }, [emblaApi, onInit, onSelect]);7980 return {81 selectedIndex,82 scrollSnaps,83 prevDisabled,84 nextDisabled,85 onDotClick,86 onPrev,87 onNext,88 };89};9091function MotionCarousel(props: PropType) {92 const { slides, options } = props;93 const [emblaRef, emblaApi] = useEmblaCarousel(options);94 const {95 selectedIndex,96 scrollSnaps,97// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from Animate UI
All 580 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Avatar Groupcomponents-animate-avatar-group | Animate UI | Components | Free | 1 dep | |
| Codecomponents-animate-code | Animate UI | Components | Free | 1 dep | |
| Code Tabscomponents-animate-code-tabs | Animate UI | Components | Free | 1 dep | |
| Cursorcomponents-animate-cursor | Animate UI | Components | Free | no deps | |
| GitHub Stars Wheelcomponents-animate-github-stars-wheel | Animate UI | Components | Free | 1 dep | |
| Tabscomponents-animate-tabs | Animate UI | Components | Free | no deps | |
| Tooltipcomponents-animate-tooltip | Animate UI | Components | Free | 1 dep | |
| Bubble Backgroundcomponents-backgrounds-bubble | Animate UI | Components | Free | 1 dep |
