This component no longer exists. It was in ruixen-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-12 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Add To Cart Button
ruixen-ui/add-to-cart-buttonRemovedComponent
A morphing add-to-cart button with spring physics, slot-machine quantity flip, and live price updates.
Live preview
live · rendered by the registry
Rendered by ruixen-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ruixen.com/r/add-to-cart-button.jsonSource
1"use client";23import { motion, AnimatePresence, type Transition } from "motion/react";4import { useState } from "react";56/**7 * Add-to-cart morphing button — Rauno Freiberg style.8 *9 * Design rules applied:10 * 1. Monochrome — neutral-900 / white / one muted accent11 * 2. Spring physics everywhere — no cubic-bezier, real springs12 * 3. One morphing container — layout animates via spring13 * 4. Content crossfades — whole phrase, not per-character14 * 5. Only transform + opacity — zero filter:blur15 * 6. Fewer elements — no pills-in-pills, no checkmarks, no icons16 * 7. Slot-machine flip — the only "flashy" detail, earned17 * 8. Hover & press feel physical — scale springs with overshoot18 */1920/* ── spring presets ── */2122const SPRING_LAYOUT: Transition = {23 type: "spring",24 stiffness: 400,25 damping: 30,26};2728const SPRING_CONTENT: Transition = {29 type: "spring",30 stiffness: 300,31 damping: 25,32};3334const SPRING_TAP: Transition = {35 type: "spring",36 stiffness: 500,37 damping: 30,38};3940/* ── component ── */4142interface AddToCartButtonProps {43 price?: number;44 currency?: string;45 maxQuantity?: number;46 onQuantityChange?: (quantity: number) => void;47}4849export function AddToCartButton({50 price = 24.99,51 currency = "$",52 maxQuantity = 99,53 onQuantityChange,54}: AddToCartButtonProps) {55 const [added, setAdded] = useState(false);56 const [qty, setQty] = useState(1);57 const [locked, setLocked] = useState(false);5859 const total = `${currency}${(price * qty).toFixed(2)}`;6061 const lock = () => {62 setLocked(true);63 setTimeout(() => setLocked(false), 350);64 };6566 const add = () => {67 if (locked) return;68 lock();69 setAdded(true);70 setQty(1);71 onQuantityChange?.(1);72 };7374 const minus = () => {75 if (qty <= 1) {76 if (locked) return;77 lock();78 setAdded(false);79 onQuantityChange?.(0);80 return;81 }82 const n = qty - 1;83 setQty(n);84 onQuantityChange?.(n);85 };8687 const plus = () => {88 const n = Math.min(qty + 1, maxQuantity);89 setQty(n);90 onQuantityChange?.(n);91 };9293 return (94 <div className="flex items-center justify-center">95 <AnimatePresence mode="popLayout" initial={false}>96 {!added ? (97 /* ────────────────────────────────────98 STATE A — "Add to cart"99 Quiet, confident, one surface.100// … truncated
What it pulls in
npm packages
