Skip to content

Import

import { InputMasked } from '@dnb/eufemia'

Description

The InputMasked component uses the basic Input component, but with input masking powered by Maskito.

When to use InputMasked vs Eufemia Forms

Classic form components like this one are presentational controls. They handle the styling, sizing, icons, and basic events, while you manage their value, validation, and error handling yourself.

For most data input and forms situations, use Eufemia Forms fields instead. They build on these same components, but add data handling, validation, and error messages through the surrounding Form.Handler. Browse the field components to find the one that matches your data.

Reach for a classic component when you need it standalone outside of a form context, or when you handle the value and validation yourself.

For masked numbers and amounts, the Eufemia Forms equivalents are Field.Number and Field.Currency. For common formatted values, use the dedicated fields such as Field.PhoneNumber, Field.NationalIdentityNumber, Field.BankAccountNumber, Field.OrganizationNumber, and Field.Expiry.

Relevant links

How it works

This component uses the basic Input component with a set of additional options and features.

You can either create your own mask using an array of RegExp and string tokens, a single RegExp, or use one of the provided number/currency masks. There are also masks that change based on different locales (asCurrency or asNumber).

Array masks define the expected input character-by-character. Each RegExp in the array represents a user-editable slot, while strings act as fixed separator tokens. For example, [/[0-9]/, /[0-9]/, ' ', /[0-9]/, /[0-9]/, ' ', /[0-9]/, /[0-9]/] creates a mask for a six-digit code with spaces after every two digits.

You can also use allowOverflow to let users type beyond the defined mask length, and overwriteMode to control how characters are overwritten (shift moves to the next slot, replace stays on the current slot).

Accessibility

Screen readers will also read the mask before the user enters the content. Additionally, the user will hear the mask during typing. This behavior can have both positive and negative side effects for the user, but overall, it works well.

Entering either 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.

Note: When pasting values that contain a dot (.) in a locale where the dot is not the native decimal or thousands separator (e.g. Norwegian), the component uses a heuristic to disambiguate: a dot followed by exactly three digits is treated as a thousands separator and removed, while any other dot is treated as a decimal separator. For example, pasting 20.500 in Norwegian locale produces 20 500 (twenty thousand five hundred), while pasting 20.5 produces 20,5 (twenty point five). Values with a leading zero (e.g. 0.500) are always treated as decimals. Be aware that a dot-decimal value with exactly three fractional digits (e.g. 2.000 meaning 2.0) will be interpreted as thousands (2 000) — this is an inherent limitation of the heuristic. Commas are only treated as thousands separators when multiple comma-separated groups appear (e.g. 1,234,567); a single trailing ,### is kept as a decimal. When both dots and commas are present (e.g. 1,234.56 or 1.234,56), the rightmost separator is always treated as the decimal and the others as thousands separators.

InputMode

NB: Please do not set inputMode="numeric" or inputMode="decimal" because devices may or may not show a minus key (-)!

The InputMasked component handles soft keyboards (iOS and Android) by using either inputMode="numeric" or 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 specified.

You can enable these masks by setting:

  • asCurrency="EUR"
  • asNumber={true}

You can still provide custom mask parameters to currencyMask={{ ... }} or numberMask={{ ... }}. Alternatively, you can use maskOptions={{ ... }} and provide your extra options there.

More details in the examples above.

Clean number values

If you use asCurrency or asNumber, you must always provide 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 pass back in:

<InputMasked
  asCurrency="EUR"
  value="1234.50"
  onChange={({ numberValue }) => {
    console.log(numberValue) // type of float
  }}
/>

Decimals

  • numberMask will default to no decimals
  • currencyMask will default to no decimals
  • asNumber will default to no decimals
  • asCurrency will 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 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 provide null and allow decimals with allowDecimal:

<InputMasked
  asNumber
  maskOptions={{
    allowDecimal: true,
    decimalLimit: null,
  }}
  value="1234.567"
/>

Related components

InputMasked is part of the Input category. Other components for similar needs:

  • Autocomplete — to help people find and choose from matching suggestions as they type.
  • Checkbox — when people can turn one or more options on or off.
  • DatePicker — when people need to choose one date or a date range.
  • Dropdown — when people need to choose one option from a list.
  • Filter — to help people narrow down a list or data set.
  • FormLabel — to name an input, control, or form-related field.

See all in Input →

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).

<Flex.Vertical>
  <InputMasked
    label="Number"
    asNumber
    maskOptions={{
      allowNegative: false,
    }}
    value="1234.50"
    onChange={({ numberValue }) => {
      console.log(numberValue)
    }}
  />
  <InputMasked
    label="Number (decimal limit)"
    asNumber
    numberMask={{
      decimalLimit: 2,
    }}
    value="1234.016"
    onChange={({ numberValue }) => {
      console.log(numberValue)
    }}
  />
  <InputMasked
    label="Percentage"
    asPercent
    numberMask={{
      decimalLimit: 1,
    }}
    value="1234.016"
    onChange={({ numberValue }) => {
      console.log(numberValue)
    }}
  />
</Flex.Vertical>

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.

<Flex.Vertical>
  <InputMasked
    label="Currency"
    asCurrency="EUR"
    value="1234.50"
    onChange={({ numberValue }) => {
      console.log(numberValue)
    }}
  />
  <Provider
    locale="en-GB"
    InputMasked={{
      currencyMask: {
        decimalLimit: 3,
      },
    }}
  >
    <InputMasked
      label="Currency"
      asCurrency="USD"
      value="1234.567"
      onChange={({ numberValue }) => {
        console.log(numberValue)
      }}
    />
  </Provider>
</Flex.Vertical>

Define the currencyMask manually

<Flex.Vertical>
  <InputMasked
    label="Left aligned (default)"
    showMask
    currencyMask="kr"
    onChange={({ numberValue }) => {
      console.log(numberValue)
    }}
  />
  <InputMasked
    label="Right aligned"
    showMask
    currencyMask={{
      currency: 'NOK',
    }}
    align="right"
    onChange={({ numberValue }) => {
      console.log(numberValue)
    }}
  />
</Flex.Vertical>

Customize the number mask

<InputMasked
  label="Masked amount"
  showMask
  numberMask={{
    suffix: ' kr',
    allowDecimal: true,
  }}
  onChange={({ numberValue }) => {
    console.log(numberValue)
  }}
/>

Using the numberMask with a combined suffix

kr
<InputMasked
  label="Masked input"
  value="1000000"
  numberMask={{
    suffix: ',-',
    allowDecimal: false,
  }}
  suffix="kr"
  onChange={({ numberValue }) => {
    console.log(numberValue)
  }}
/>

Using the numberMask and a prefix

<InputMasked
  label="Masked input"
  numberMask={{
    prefix: 'NOK ',
  }}
  stretch={true}
  placeholder="Enter a number"
  onChange={({ numberValue }) => {
    console.log(numberValue)
  }}
/>