Import
import { InputMasked } from '@dnb/eufemia'
Description
The InputMasked component uses the basic Input component, but with some additional masking functionality.
Relevant links
How it works
This component uses the basic Input but with a set of options and features.
You will either create your own mask, or use one of the provided once. There are also masks which change based on different locales (asCurrency or asNumber).
Accessibility
Screen readers will read also the mask before the user is entering the content. Also, the user will hear the mask during typing. This behavior can both have positive and negative side effects on the user. But overall, it works ok.
Both entering a comma or a dot will act as a decimal separator if decimals are enabled and one of the internal masks for numbers is used.
InputMode
NB: Please do not set inputMode="numeric" or inputMode="decimal", because devices may or may not show a minus key (-)!
The InputMasked component does handle soft keyboards (iOS and Android) by using either inputMode="numeric" and inputMode="decimal" depending on allowNegative and allowDecimal (getSoftKeyboardAttributes).
For iOS it additionally sets type="number" during focus (InputModeNumber). This way the correct numeric soft keyboard is shown.
<InputMasked maskOptions={{ allowNegative: false, }} />
Mask based on locale
The InputMasked component supports masks based on a given locale. The locale will be inherited from the Eufemia Provider if not given.
As of now, you can enable these masks by giving:
asCurrency="EUR"asNumber={true}
You can still send in custom mask parameters to currencyMask={{ ... }} or numberMask={{ ... }}. But you can also make use of maskOptions={{ ... }} and just send in your extra options in there.
More details in the examples above.
Clean number values
If you use asCurrency or asNumber you have to always send in in a clean number without any mask (value="1234.50"):
<InputMasked asCurrency="EUR" value="1234.50" />
You can also receive a clean number value you can use and send back in again:
<InputMasked asCurrency="EUR" value="1234.50" on_change={({ numberValue }) => { console.log(numberValue) // type of float }} />
Decimals
numberMaskwill default to no decimalscurrencyMaskwill default to no decimalsasNumberwill default to no decimalsasCurrencywill default to 2 decimals
You can change the number of decimals by sending in options to the currencyMask, numberMask, or maskOptions (see example above).
This example here also shows how to affect every InputMasked component in your application, by setting these options on the Eufemia Provider.
<Provider locale="en-GB" InputMasked={{ currencyMask: { decimalLimit: 1, // defaults to 2 }, }} > <InputMasked asCurrency="USD" value="1234.567" /> </Provider>
<Provider locale="en-GB" InputMasked={{ numberMask: { decimalLimit: 2, // defaults to no decimals }, }} > <InputMasked asNumber value="1234.567" /> </Provider>
To remove a decimal limit, you can send in null and allow decimals with allowDecimal:
<InputMasked asNumber maskOptions={{ allowDecimal: true, decimalLimit: null, }} value="1234.567" />
Mask with multiple inputs
Allows for the same input functionality as in the DatePicker, but with your own defined inputs.
onChange takes an object with keys based on the step id's. e.g. {month: string, year: string, suffix: string}
import as demonstrated below
import { MultiInputMask } from '@dnb/eufemia/components/input-masked'render(<MultiInputMask />)
<MultiInputMask label="Date" delimiter="/" onChange={({ month, year, suffix }) => console.log({ month, year, suffix, }) } inputs={[ { id: 'month', label: 'the month', placeholderCharacter: 'd', mask: [/[0-9]/, /[0-9]/], }, { id: 'year', label: 'the year', placeholderCharacter: 'm', mask: [/[0-9]/, /[0-9]/], }, { id: 'suffix', label: 'suffix text', placeholderCharacter: '-', mask: [/[a-zA-Z]/, /[a-zA-Z]/, /[a-zA-Z]/], }, ]} />
Demos
Locale based numbers
When you use asNumber or asPercent (and asCurrency see below) it will create a mask for you and inherit the locale from the Eufemia Provider, if the locale property is not given.
You can still define extra mask parameters with numberMask or maskOptions, as the second input example shows (e.g. decimalLimit).
<Provider formElement={{ labelDirection: 'vertical', }} > <Flex.Vertical> <InputMasked label="Number" asNumber maskOptions={{ allowNegative: false, }} value="1234.50" on_change={({ numberValue }) => { console.log(numberValue) }} /> <InputMasked label="Number (decimal limit)" asNumber numberMask={{ decimalLimit: 2, }} value="1234.016" on_change={({ numberValue }) => { console.log(numberValue) }} /> <InputMasked label="Percentage" asPercent numberMask={{ decimalLimit: 1, }} value="1234.016" on_change={({ numberValue }) => { console.log(numberValue) }} /> </Flex.Vertical> </Provider>
Locale based asCurrency
When you use asCurrency it will create a mask for you and inherit the locale from the Eufemia Provider, if the locale property is not given.
<Provider formElement={{ labelDirection: 'vertical', }} > <Flex.Vertical> <InputMasked label="Currency" asCurrency="EUR" value="1234.50" on_change={({ numberValue }) => { console.log(numberValue) }} /> <Provider locale="en-GB" InputMasked={{ currencyMask: { decimalLimit: 3, }, }} > <InputMasked label="Currency" asCurrency="USD" value="1234.567" on_change={({ numberValue }) => { console.log(numberValue) }} /> </Provider> </Flex.Vertical> </Provider>
Define the currencyMask manually
<Provider formElement={{ labelDirection: 'vertical', }} > <Flex.Vertical> <InputMasked label="Left aligned (default)" showMask currencyMask="kr" on_change={({ numberValue }) => { console.log(numberValue) }} /> <InputMasked label="Right aligned" showMask currencyMask={{ currency: 'NOK', }} align="right" on_change={({ numberValue }) => { console.log(numberValue) }} /> </Flex.Vertical> </Provider>
Customize the number mask
<InputMasked label="Masked amount" showMask numberMask={{ suffix: ' kr', allowDecimal: true, }} placeholderChar={null} on_change={({ numberValue }) => { console.log(numberValue) }} />
Using the numberMask with a combined suffix
<InputMasked label="Masked input" value="1000000" numberMask={{ suffix: ',-', allowDecimal: false, }} suffix="kr" on_change={({ numberValue }) => { console.log(parseInt(numberValue || 0, 10)) }} />
Using the numberMask and a prefix
<InputMasked label="Masked input" numberMask={{ prefix: 'NOK ', }} stretch={true} placeholder="Enter a number" on_change={({ numberValue }) => { console.log(numberValue) }} />
Custom mask
This is an example of how you can utilize a custom mask.
For a phone number input, use the Field.PhoneNumber field instead.
<InputMasked label="Custom mask" mask={[ '0', '0', /[4]/, // have to start with 4 /[5-7]/, // can be 5,6 or 7 ' ', /[49]/, // have to start with 4 or 9 /\d/, ' ', /\d/, /\d/, ' ', /\d/, /\d/, ' ', /\d/, /\d/, ]} showMask placeholderChar="_" keepCharPositions on_change={({ numberValue }) => { console.log(numberValue) }} />
Mask with multiple inputs
Allows for the same input functionality as in the DatePicker, but with your own defined inputs.
onChange takes an object with keys based on the step id's. e.g. {month: string, year: string, suffix: string}
import as demonstrated below
import { MultiInputMask } from '@dnb/eufemia/components/input-masked'render(<MultiInputMask />)
<MultiInputMask label="Date" delimiter="/" onChange={({ month, year, suffix }) => console.log({ month, year, suffix, }) } inputs={[ { id: 'month', label: 'the month', placeholderCharacter: 'd', mask: [/[0-9]/, /[0-9]/], }, { id: 'year', label: 'the year', placeholderCharacter: 'm', mask: [/[0-9]/, /[0-9]/], }, { id: 'suffix', label: 'suffix text', placeholderCharacter: '-', mask: [/[a-zA-Z]/, /[a-zA-Z]/, /[a-zA-Z]/], }, ]} />