Money input

All copy is placeholder. Real strings come from the i18n layer.

Default, focused, error, read-only

Tab into the currency — the ring is raised so the input beside it cannot clip it.

Read from the linked expense. Change it in Money and this follows.

The invalid field keeps what was typed. Clearing it to "fix" it loses the only copy of what they meant.

The digit count comes from the currency

Never a constant. The same stored integer is three different amounts.

CurrencyMinor digitsStoredShown
JPY012000¥12,000
EUR212000€120.00
KWD312000KD12.000
Changing the currency must re-validate the amount, not just relabel it: 12.5 is valid in EUR and not in JPY.

And the separators come from the locale

TypedIn EnglishIn Turkish
1.234,50malformedone thousand two hundred and thirty-four fifty
1,234.50one thousand two hundred and thirty-four fiftymalformed
The same keystrokes are two different numbers in the two languages this product ships. A component that hardcodes . as the decimal point is wrong for half its users on day one — ADR-0014.

Never type="number"

Spinners are meaningless for money, the scroll wheel changes values by accident, and browsers disagree about what a comma does in one. inputmode="decimal" gets the numeric keypad on a phone without any of that.