Currency Input
CurrencyInput is a headless locale-aware text input for entering currency values with automatic formatting, currency symbols, thousand separators, and correct decimal places. It supports 40+ world currencies including USD, EUR, GBP, and JPY.
Use CurrencyInput for payment forms, price fields, budget inputs, and any form field that accepts monetary values. The component uses inputmode="decimal" for appropriate mobile keyboards and formats the display value while maintaining a clean numeric value for form submission.
Implementation Notes
- Renders a native
<input>element withtype="text"andinputmode="decimal" - Uses
aria-labelfor an accessible name describing the input purpose - The
valueprop uses two-way binding with an initial undefined state - Supports
minandmaxvalue constraints - Supports
requiredanddisabledboolean states - Spreads
restPropsonto the input for consumer customization (e.g.,id,name,placeholder) - The
currencyCodeprop accepts ISO 4217 currency codes (e.g., "USD", "EUR", "GBP", "JPY") - Formatting is handled by the consumer or by using the Intl.NumberFormat API
- pattern:
two-way bindingfor the value prop
Props
label: string (required) -- accessible name for the input viaaria-labelvalue: number | undefined (default:undefined) -- current numeric value; bindable with two-way bindingcurrencyCode: string (default:"USD") -- ISO 4217 currency code for formattingmin: number (optional) -- minimum allowed valuemax: number (optional) -- maximum allowed valuerequired: boolean (default:false) -- whether the input is requireddisabled: boolean (default:false) -- whether the input is disabled...restProps: unknown -- additional attributes spread onto the<input>element
Usage
Basic USD price input:
<CurrencyInput label="Price" value={amount} currencyCode="USD" />
EUR budget input with min/max constraints:
<CurrencyInput label="Annual budget" value={budget} currencyCode="EUR" min={0} max={10000} />
JPY total input (no decimal places):
<CurrencyInput label="Total" value={total} currencyCode="JPY" required />
Currency input in a payment form:
<Form label="Payment details" onsubmit={handlePayment}>
<Field label="Payment amount" required>
<CurrencyInput label="Payment amount" value={paymentAmount} currencyCode="GBP" min={1} required />
</Field>
<Field label="Tip (optional)">
<CurrencyInput label="Tip amount" value={tipAmount} currencyCode="GBP" min={0} />
</Field>
<Button type="submit">Pay now</Button>
</Form>
Keyboard Interactions
None at the component level. Keyboard behavior is handled natively by the browser's text input implementation. Consumers may add increment/decrement via arrow keys if desired.
ARIA
aria-label={label}-- provides an accessible name describing the purpose of the currency inputinputmode="decimal"-- triggers a numeric keyboard with decimal point on mobile devices
When to Use
- Use for form fields that accept monetary values, such as prices, budgets, payment amounts, or salary fields.
- Use when you need locale-aware currency formatting with proper symbols and separators.
- Use in checkout flows, invoicing forms, or financial dashboards where currency context matters.
- Use when the ISO 4217 currency code needs to be associated with the input value.
When Not to Use
- Do not use for non-currency numbers -- use NumberInput instead.
- Do not use for displaying formatted amounts in read-only context -- format the text inline instead.
- Do not use for entering quantities or measurements -- use NumberInput or MeasurementInstanceInput instead.
Headless
This headless component wraps a native <input type="text"> with inputmode="decimal", aria-label for accessible naming, two-way bindable value, and optional min, max constraints. The consumer provides all visual styling, including currency symbol display, input dimensions, borders, and validation error display. Formatting logic (thousand separators, decimal places, currency symbols) can be implemented by the consumer using Intl.NumberFormat or similar APIs.
Styles
The consumer provides all CSS styling. The component renders with a .currency-input class for targeting. Common styling concerns include right-aligned text, currency symbol positioning (prefix or suffix), and font-variant-numeric: tabular-nums for consistent digit widths.
Testing
- Verify the component renders an
<input>element withtype="text" - Verify
aria-labelis set from thelabelprop - Verify
inputmode="decimal"is present for mobile keyboard support - Verify
disabledandrequiredattributes propagate correctly - Verify pass-through attributes are applied to the input
Advice
- Designers: Display the currency symbol clearly near the input. Use right-aligned text and tabular numbers for consistent formatting. Show the expected currency format as placeholder text.
- Developers: Use
Intl.NumberFormatwith the appropriate locale and currency code for formatting display values. Be aware that different currencies have different decimal place requirements (e.g., JPY uses 0, USD uses 2). Validate and clamp values on blur rather than on every keystroke.
Related components
text-input— a single-line text input field <input type="text">
References
- HTML text input: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text
- Intl.NumberFormat: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
- ISO 4217 Currency Codes: https://www.iso.org/iso-4217-currency-codes.html