Currency Input — Money Formatting HTML CSS JS Snippet

Currency Input · Forms · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Live thousands separators
The grouping regex /\B(?=(\d{3})+(?!\d))/g inserts commas before every three-digit group as the user types — no library.
Display vs stored value
The field shows a grouped, symbol-prefixed string while updateParsed maintains the clean numeric value ("1250.00") for submission.
Two-decimal clamp
formatMoney splits at the first dot, drops extra dots, and limits the decimal to two places, so amounts stay valid.
Leading-zero cleanup
Leading zeros are stripped from the integer part so "007" becomes "7" while an in-progress "0." is preserved.
Currency switcher
A <select> updates the prefix symbol ($/€/£/₹/¥) and the displayed currency code via setCurrency.
Unified focus ring
:focus-within highlights the whole field — symbol, input, and selector — so the composite reads as one control.
Quick-add chips
setAmount adds a delta to the current value and reformats, ideal for tips, top-ups, and donations.
Mobile numeric keypad
inputmode="decimal" triggers the numeric keypad on phones while keeping the formatted text value.

About this UI Snippet

Currency Input — Live Thousands Separators, Decimal Clamping & Currency Switcher

Screenshot of the Currency Input snippet rendered live

Money inputs are deceptively tricky. Users expect to see "1,250.00" with thousands separators as they type, but your application needs the clean numeric value "1250.00" to store and calculate with. A naive <input type="number"> cannot show grouping separators, and a plain text field lets users type anything. This snippet implements a proper currency field in plain HTML, CSS, and vanilla JavaScript: live thousands-separator formatting, a two-decimal clamp, a currency symbol switcher, quick-add chips, and a parsed value kept in sync for submission.

Live formatting that keeps a clean stored value

formatMoney runs on every keystroke. It strips everything except digits and a decimal point, splits at the first dot into integer and decimal parts, discards any extra dots, clamps the decimal to two places, and removes leading zeros. The integer part then gets thousands separators via the standard grouping regex /\B(?=(\d{3})+(?!\d))/g, which inserts a comma before every group of three digits that is preceded by another digit. The formatted string goes back into the field, while updateParsed strips the commas and shows the canonical numeric value ("1250.00") — the value you would actually submit to a server.

Why the display and stored value differ

This separation is the core idea. The visible field is for humans (grouped, symbol-prefixed); the stored value is for machines (a plain number). Keeping both in sync on every input means the user never sees an unformatted number and your code never has to parse a comma-laden string at submit time — updateParsed already maintains the clean value.

Currency switcher

A compact <select> lets the user switch currency. setCurrency updates the prefix symbol ($, €, £, ₹, ¥) and the stored currency code shown beside the value. The symbol sits in the field as a prefix via flexbox, and :focus-within lights up the whole field (not just the bare input) so the symbol, input, and selector read as one control.

Quick-add chips

Buttons like "+50" and "+1,000" call setAmount, which reads the current numeric value, adds the delta, and re-runs formatMoney — handy for tip jars, top-ups, and donation fields where users nudge an amount rather than type it precisely.

Mobile-friendly

inputmode="decimal" brings up the numeric keypad on mobile while still allowing the formatted text value, the best of both worlds for a money field.

Pair this with an order summary for totals, a tip calculator or currency converter for math, or a checkout payment form.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to trace the regex by eye to trust it. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly what the grouping regex in formatMoney matches and why it inserts commas only before digit groups that already have another digit ahead of them. The same assistant can help you optimize it — ask whether reformatting on every keystroke could be debounced for very long numbers without hurting the live-typing feel, or whether the caret-jumps-to-end behavior is worth fixing with setSelectionRange for a smoother typing experience. It's also useful for extending the field: ask it to add locale-aware separators for currencies that use a comma as the decimal point instead of the thousands separator, a maximum-amount clamp with an inline warning, or a hidden input that always mirrors the clean numeric value for native form submission. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a currency input field in plain HTML, CSS, and JavaScript that live-formats as the user types — no input masking library.

Requirements:
- A text input (not type="number", so grouping characters can be displayed) with inputmode="decimal" so mobile devices show a numeric keypad.
- A formatMoney function that runs on every input event: strip everything except digits and a single decimal point, split at the first decimal point into an integer part and a decimal part, discard any additional decimal points typed, and clamp the decimal part to at most two digits.
- Strip leading zeros from the integer part (so "007" becomes "7") while still allowing an in-progress value like "0." to remain as the user types it.
- Insert thousands-separator commas into the integer part using a regex that only inserts a comma before a group of exactly three digits that itself has at least one more digit before it, so the grouping never puts a stray comma at the very start of the number.
- Maintain a second, separate "stored value" display element that always shows the clean unformatted number (no commas) parsed from the visible field, so the UI clearly demonstrates the difference between what the user sees and what a server would actually receive.
- Add a currency selector that changes both a prefix symbol shown inside the field and a currency code shown next to the stored value, and style the field so the whole composite control (symbol, input, and selector) highlights together on focus.
- Add a few quick-add chip buttons that add a fixed delta to the current numeric value and re-run the formatter.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA money field shows "$ 1,250.00" with a currency selector, quick-add chips, and a "Stored value: 1250.00 USD" readout.
  2. 2
    Type an amountEnter digits — thousands separators appear automatically and the decimal is clamped to two places as you type.
  3. 3
    Watch the stored valueBelow the field, the clean numeric value (no commas) updates live — that is what you would submit to a server.
  4. 4
    Switch currencyPick EUR or INR from the selector — the prefix symbol and the currency code beside the stored value change.
  5. 5
    Use the quick chipsClick "+100" or "+1,000" to bump the amount; the field reformats with the new total.
  6. 6
    Read it for submissionOn submit, use the parsed value (updateParsed keeps it in sync) instead of the comma-formatted display string.

Real-world uses

Common Use Cases

Checkout and payment amounts
Enter a custom charge or payment with proper grouping. Combine with a checkout payment form and order summary.
Donation and tip fields
Quick-add chips make it easy to bump a donation; pair with a tip calculator for split math.
Budgeting and finance apps
Money inputs for budgets, transfers, and goals where grouped display and a clean stored value both matter.
Invoicing and quoting tools
Enter line-item amounts that feed an invoice preview total with consistent formatting.
Pricing and quote calculators
Drive a usage calculator or currency converter from a properly formatted amount field.
Crypto and multi-currency wallets
The currency switcher adapts the symbol/code; extend the decimals for high-precision assets.

Got questions?

Frequently Asked Questions

Use the parsed value, not the formatted text. updateParsed already computes parseFloat(value.replace(/,/g, '')) and shows it; read that on submit, or store it in a hidden input. Never send the comma-formatted display string to your backend — strip the separators first so "1,250.00" becomes the number 1250.

Some locales use "." for grouping and "," for decimals (e.g. 1.250,00). Map each currency/locale to its separators and parameterise formatMoney accordingly, or use Intl.NumberFormat(locale, { style: 'currency', currency }) to format and a matching parser to read it back. The display/stored-value split stays the same.

Reformatting replaces the field value, which resets the caret. This snippet keeps it simple (caret at end), which is fine for amount fields typed left-to-right. To preserve caret position precisely, count the digits before the caret, reformat, then restore the caret after the same number of digits using setSelectionRange.

In updateParsed, after computing the number, clamp it (e.g. Math.min(num, MAX)) and, if it changed, reformat the field to the clamped value and show a hint. For minimums, validate on blur rather than per keystroke so users can type intermediate values without being interrupted.

In React, keep the raw numeric value in state and a derived formatted string for display; format in the onChange handler before setting state, or use a controlled value with a formatter. In Vue, use v-model with a computed/watcher that formats. In Angular, a custom ControlValueAccessor or a pipe handles formatting. The grouping regex and decimal logic port unchanged.