2
React + MotionInputs

Selector de cantidad

Botones de menos y más alrededor de una cifra que sube o baja deslizándose cada vez que cambia.

Ajustes

2
12

Código

import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Minus, Plus } from "lucide-react";

interface AnimatedQuantityProps {
  value?: number;
  defaultValue?: number;
  max?: number;
  onChange?: (value: number) => void;
}

export default function AnimatedQuantity({
  value,
  defaultValue = 2,
  max = 12,
  onChange,
}: AnimatedQuantityProps) {
  const [internal, setInternal] = useState(defaultValue);
  const n = value ?? internal;

  const set = (next: number) => {
    if (value === undefined) setInternal(next);
    onChange?.(next);
  };

  return (
    <div className="flex items-center gap-5 rounded-full bg-white p-2 text-[#1d1d1f] shadow-[0_1px_2px_rgba(0,0,0,0.03),0_8px_28px_rgba(0,0,0,0.05)] dark:bg-[#1c1c1e] dark:text-[#f5f5f7]">
      <button
        type="button"
        aria-label="Restar"
        onClick={() => set(Math.max(0, n - 1))}
        className="grid h-9 w-9 place-items-center rounded-full bg-black/5 dark:bg-white/10"
      >
        <Minus className="h-4 w-4" />
      </button>
      <AnimatePresence mode="popLayout" initial={false}>
        <motion.strong
          key={n}
          initial={{ y: 12, opacity: 0 }}
          animate={{ y: 0, opacity: 1 }}
          exit={{ y: -12, opacity: 0 }}
          className="w-7 text-center"
        >
          {n}
        </motion.strong>
      </AnimatePresence>
      <button
        type="button"
        aria-label="Sumar"
        onClick={() => set(Math.min(max, n + 1))}
        className="grid h-9 w-9 place-items-center rounded-full bg-black/5 dark:bg-white/10"
      >
        <Plus className="h-4 w-4" />
      </button>
    </div>
  );
}

Prompt para IA

Pégalo en ChatGPT, Claude o Cursor y adaptará el bloque a tu proyecto con estos ajustes, aunque no uses React.

Más en Inputs

Dónde usarlo

El selector de cantidad aparece allí donde se pide algo: el carrito de una tienda online, las entradas de un concierto o las raciones de una app de comida. La cifra que se desliza hace visible cada toque, y nadie añade tres botellas de vino sin querer. Parece un control aburrido, pero se toca más que casi ningún otro.

Pon un máximo con sentido para tu caso, como el stock real o el tope de entradas por pedido. Por defecto se para en cero; si el cero no tiene sentido, por ejemplo en una línea del carrito, empieza el mínimo en uno.