All Taste components
Inputs
Number stepper
A small count you nudge up or down, with limits that disable the buttons.
default · at minimum · with sub-label · small
Adults
Ages 13 or above
Children
Ages 2–12
Infants
Under 2
Masala dosa · ₹120
"use client";
import { Minus, Plus } from "lucide-react";
import { cn } from "@/lib/utils";
const sizes = {
sm: { box: "h-[30px]", btn: "w-7 [&_svg]:size-3.5", input: "w-8 text-[13px]" },
md: { box: "h-9", btn: "w-[34px] [&_svg]:size-4", input: "w-10 text-sm" },
};
export function NumberStepper({ label, value, onChange, min = 0, max = 99, size = "md" }:
{ label: string; value: number; onChange: (v: number) => void; min?: number; max?: number; size?: keyof typeof sizes }) {
const s = sizes[size];
const set = (v: number) => onChange(Math.min(max, Math.max(min, v)));
const btn = cn(
"grid place-items-center text-fg-muted transition hover:bg-surface-2 hover:text-fg",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
"disabled:pointer-events-none disabled:opacity-45",
s.btn,
);
return (
<div role="group" aria-label={label} className={cn("inline-flex shrink-0 items-stretch overflow-hidden rounded border border-border-strong bg-bg", s.box)}>
<button type="button" aria-label={"Decrease " + label.toLowerCase()} disabled={value <= min} onClick={() => set(value - 1)} className={btn}>
<Minus aria-hidden />
</button>
<input
role="spinbutton"
inputMode="numeric"
aria-label={label}
aria-valuenow={value}
aria-valuemin={min}
aria-valuemax={max}
value={value}
onChange={(e) => { const n = parseInt(e.target.value, 10); set(Number.isNaN(n) ? min : n); }}
onKeyDown={(e) => {
if (e.key === "ArrowUp") { e.preventDefault(); set(value + 1); }
if (e.key === "ArrowDown") { e.preventDefault(); set(value - 1); }
}}
className={cn("border-x border-border bg-transparent text-center font-medium tabular-nums text-fg outline-none focus:bg-surface", s.input)}
/>
<button type="button" aria-label={"Increase " + label.toLowerCase()} disabled={value >= max} onClick={() => set(value + 1)} className={btn}>
<Plus aria-hidden />
</button>
</div>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.