Review
Mobile-friendly custom tip amount field
Checkout tip sheet still used type=number, which opens a full keyboard on iOS and lets spinners mess with cents. Switches to a controlled text field with inputMode=decimal and sanitizes to digits plus a single decimal point.
ReactTier 1mobileformsux
Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.
components/checkout/CustomTipInput.tsx+17-11
| 18 | 18 | export function CustomTipInput({ value, onChange }: Props) { | |
| 19 | - | return ( | |
| 20 | - | <input | |
| 21 | - | type="number" | |
| 22 | - | step="0.01" | |
| 23 | - | min={0} | |
| 24 | - | value={value} | |
| 25 | - | onChange={(e) => onChange(Number(e.target.value))} | |
| 26 | - | placeholder="0.00" | |
| 27 | - | aria-label="Custom tip amount" | |
| 28 | - | /> | |
| 29 | - | ); | |
| 19 | + | function sanitizeAmount(raw: string): string { | |
| 20 | + | const cleaned = raw.replace(/[^0-9.]/g, ""); | |
| 21 | + | const [whole, ...rest] = cleaned.split("."); | |
| 22 | + | if (rest.length === 0) return whole; | |
| 23 | + | return `${whole}.${rest.join("").slice(0, 2)}`; | |
| 24 | + | } | |
| 30 | 25 | ||
| 26 | + | return ( | |
| 27 | + | <input | |
| 28 | + | type="text" | |
| 29 | + | inputMode="decimal" | |
| 30 | + | autoComplete="off" | |
| 31 | + | value={value} | |
| 32 | + | onChange={(e) => onChange(sanitizeAmount(e.target.value))} | |
| 33 | + | placeholder="0.00" | |
| 34 | + | aria-label="Custom tip amount" | |
| 35 | + | /> | |
| 36 | + | ); | |
| 31 | 37 | } |