InputsReact
A text input for an amount of money in one currency, formatted as it is typed: $1,234.56 in English, 1.234,56 € in German, lakh groups in India and Arabic-Indic digits in Egypt.
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<CurrencyInput.Root>
<CurrencyInput.Input />
</CurrencyInput.Root>
// Not in this example: CurrencyInput.SymbolExamples
Transfer
An amount held by the app with a currency picked beside it; the yen rounds it once, the dinar shows three decimals.
Locale
The same euro amount in five locales: groups, the decimal mark, Arabic-Indic digits and the symbol's side.
Outside
currencyPlacement="outside" with a Symbol after the amount, as German writes the euro, and a label naming the currency.
Accounting
A balance shown in parentheses when negative and with a minus sign while edited, said in Field.Description.
Fixed Decimal
fixedDecimalEntry: the digits fill the amount from the cents, as on a payment terminal.
Validation
A transfer from $10.00 to $5,000.00, with a message for each bound when the field is left.
Form
A required amount with a max in a form, with a message for a missing and a too large amount, and a reset.
API reference
24 props across 3 parts, in React syntax. className, style, render are listed once, under Shared props.
InputCurrencyInput.Input
The text input that shows the amount formatted while the user types. It is the field's labelled control; its value is the Root's. Renders an <input>.
| Prop | Type | Default |
|---|---|---|
typeThe input's type. | "text" | 'text' |
inputModeThe virtual keyboard to show. | "search" | "text" | "none" | "tel" | "url" | "email" | "numeric" | "decimal" | — |
autoCompleteThe autocomplete hint, such as 'transaction-amount'. | React.HTMLInputAutoCompleteAttribute | 'off' |
autoCorrectThe autocorrect hint for virtual keyboards. | string | 'off' |
spellCheckWhether the browser checks the spelling of the value. | Booleanish | false |
| Data attribute | Description |
|---|---|
data-negative | Present when the value is below zero. |
data-disabled | Present when the currency input is disabled. |
data-readonly | Present when the currency input is readonly. |
data-required | Present when the currency input is required. |
data-valid | Present when the currency input is in a valid state (when wrapped in Field.Root). |
data-invalid | Present when the currency input is in an invalid state (when wrapped in Field.Root). |
data-touched | Present when the currency input has been touched (when wrapped in Field.Root). |
data-dirty | Present when the currency input's value has changed (when wrapped in Field.Root). |
data-filled | Present when the currency input has a value. |
data-focused | Present when the input is focused. |
RootCurrencyInput.Root
Groups the currency input and its symbol, holds the amount, and renders the hidden input the form submits. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
currencyrequiredThe ISO 4217 code of the currency, such as 'USD'. | string | — |
localeThe locale that formats the amount. | Intl.LocalesArgument | — |
formatIntl.NumberFormat options: currencyDisplay, currencySign, useGrouping, | CurrencyInputFormat | — |
currencyPlacementWhether the currency text is part of the input's text, or drawn by CurrencyInput.Symbol | CurrencyInputPlacement | 'inline' |
valueThe amount as a canonical decimal string, null when empty. | string | null | — |
defaultValueThe amount when the component is initially rendered, and the amount a form reset restores. | string | null | null |
onValueChangeCallback fired when the amount changes. | ((value: string | null, eventDetails: CurrencyInputRootChangeEventDetails) => void) | — |
onValueCommittedCallback fired when the input loses focus after the user changed the amount. | ((value: string | null, eventDetails: CurrencyInputRootCommitEventDetails) => void) | — |
onValueInvalidCallback fired when typed, pasted or dropped text is refused. | ((value: string, eventDetails: CurrencyInputRootInvalidEventDetails) => void) | — |
minThe smallest valid amount. | string | number | — |
maxThe largest valid amount. | string | number | — |
formatOnBlurWhether the input shows the plain amount while focused and the formatted text otherwise. | boolean | false |
fixedDecimalEntryWhether typed digits fill the amount from its last fraction digit, so typing 1 0 2 5 | boolean | false |
nameIdentifies the field when a form is submitted. | string | — |
formThe id of the form element the hidden input belongs to. | string | — |
requiredWhether the user must enter a value before submitting a form. | boolean | false |
disabledWhether the component should ignore user interaction. | boolean | false |
readOnlyWhether the user should be unable to change the value. | boolean | false |
inputRefA ref to the hidden input that holds the form value. | React.Ref<HTMLInputElement> | — |
| Data attribute | Description |
|---|---|
data-negative | Present when the value is below zero. |
data-disabled | Present when the currency input is disabled. |
data-readonly | Present when the currency input is readonly. |
data-required | Present when the currency input is required. |
data-valid | Present when the currency input is in a valid state (when wrapped in Field.Root). |
data-invalid | Present when the currency input is in an invalid state (when wrapped in Field.Root). |
data-touched | Present when the currency input has been touched (when wrapped in Field.Root). |
data-dirty | Present when the currency input's value has changed (when wrapped in Field.Root). |
data-filled | Present when the currency input has a value. |
data-focused | Present when the input is focused. |
SymbolCurrencyInput.Symbol
The currency text drawn outside the input when currencyPlacement is 'outside', with the side the locale puts it on. Hidden from assistive technology. Renders a <span>.
| Data attribute | Description |
|---|---|
data-side | Indicates the side of the amount the locale puts the currency on, in logical order. |
data-negative | Present when the value is below zero. |
data-disabled | Present when the currency input is disabled. |
data-focused | Present when the input is focused. |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| Inserts the digit at the caret; the groups are written again and the caret follows it | Input | |
| A letter or another character the amount does not take changes nothing | Input | |
| ., | Types the decimal mark, whatever the locale writes | Input |
| - | Changes the sign; the caret keeps its place | Input |
| Backspace | Deletes the digit before the caret, past the group marks | Input |
| BackspaceDelete | Next to the decimal mark, moves the caret over it instead of joining the digits | Input |
| ControlZMetaZ | Undoes the last edit; Meta+Z on Apple platforms | Input |
| ControlShiftZControlY | Redoes the edit undone last | Input |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Input | a plain input with no role, no aria-roledescription and no aria-valuenow; value is the formatted text | it is read as the text field it is, with the amount the user sees |
| Input | aria-labelledby the Field label, aria-describedby its description and errors, aria-invalid, aria-required | the name, the currency, the error and the rule are said with the field |
| Input | inputmode decimal (numeric for a currency with no decimals, text on iOS when negatives are allowed), autocorrect off, spellcheck false | the keyboard has the keys the amount needs, and nothing rewrites the text by itself |
| Input | a minus sign (U+2212) for a negative amount while focused, the accounting parentheses only while not focused | screen readers say "minus" where they would skip a hyphen or the parentheses |
| Symbol | aria-hidden="true", no role | the currency is seen beside the field and said by its label, not twice |
| Root | the hidden input type="number" with tabindex="-1", aria-hidden="true", name, required, min, max and step="any" | the form value and its validity never add a stop or a name |
Focus order
- The Input is one tab stop; the Symbol and the hidden input are never focused.
- Focus by Tab, by the label or by the app keeps the selection the browser puts there; nothing takes focus on mount or on a form reset.