deck
kibo-ui-registry/deckFreeComponent
A Tinder-like swipeable card stack component with smooth animations.
Live preview
live · rendered by the registry
Rendered by Kibo UI Registry on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://www.kibo-ui.com/r/deck.jsonSource
1"use client";23import { useControllableState } from "@radix-ui/react-use-controllable-state";4import {5 motion,6 type PanInfo,7 useMotionValue,8 useTransform,9} from "motion/react";10import {11 Children,12 cloneElement,13 type HTMLAttributes,14 type ReactElement,15 useCallback,16 useEffect,17 useRef,18 useState,19} from "react";20import { cn } from "@/lib/utils";2122export type DeckProps = HTMLAttributes<HTMLDivElement>;2324export const Deck = ({ className, ...props }: DeckProps) => (25 <div className={cn("relative isolate", className)} {...props} />26);2728export type DeckCardsProps = HTMLAttributes<HTMLDivElement> & {29 onSwipe?: (index: number, direction: "left" | "right") => void;30 onSwipeEnd?: (index: number, direction: "left" | "right") => void;31 threshold?: number;32 stackSize?: number;33 perspective?: number;34 scale?: number;35 currentIndex?: number;36 defaultCurrentIndex?: number;37 onCurrentIndexChange?: (index: number) => void;38 animateOnIndexChange?: boolean;39 indexChangeDirection?: "left" | "right";40};4142export const DeckCards = ({43 children,44 className,45 onSwipe,46 onSwipeEnd,47 threshold = 150,48 stackSize = 3,49 perspective = 1000,50 scale = 0.05,51 currentIndex: currentIndexProp,52 defaultCurrentIndex = 0,53 onCurrentIndexChange,54 animateOnIndexChange = true,55 indexChangeDirection = "left",56 ...props57}: DeckCardsProps) => {58 const childrenArray = Children.toArray(children) as ReactElement[];59 const [currentIndex, setCurrentIndex] = useControllableState({60 prop: currentIndexProp,61 defaultProp: defaultCurrentIndex,62 onChange: onCurrentIndexChange,63 });64 const [exitDirection, setExitDirection] = useState<"left" | "right" | null>(65 null66 );67 const [displayIndex, setDisplayIndex] = useState(currentIndex);68 const isInternalChangeRef = useRef(false);69 const prevIndexRef = useRef(currentIndex);7071 // Detect external currentIndex changes and trigger animation72 useEffect(() => {73 const prevIndex = prevIndexRef.current;7475 // Skip initial mount and internal changes76 if (prevIndex === currentIndex || isInternalChangeRef.current) {77 isInternalChangeRef.current = false;78 prevIndexRef.current = currentIndex;79 setDisplayIndex(currentIndex);80 return;81 }8283 // Only animate if the option is enabled and we have cards to show84 if (animateOnIndexChange && prevIndex < childrenArray.length) {85 setExitDirection(indexChangeDirection);8687 // Update display index after animation completes88// … truncated
What it pulls in
npm packages
Files it writes
More from Kibo UI Registry
All 41 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| announcementannouncement | Kibo UI Registry | Components | Free | no deps | |
| avatar-stackavatar-stack | Kibo UI Registry | Components | Free | no deps | |
| bannerbanner | Kibo UI Registry | Components | Free | 2 deps | |
| calendarcalendar | Kibo UI Registry | Components | Free | 3 deps | |
| choiceboxchoicebox | Kibo UI Registry | Components | Free | 2 deps | |
| code-blockcode-block | Kibo UI Registry | Components | Free | 5 deps · 2 files | |
| color-pickercolor-picker | Kibo UI Registry | Components | Free | 3 deps | |
| comboboxcombobox | Kibo UI Registry | Components | Free | 2 deps |
