Skip to content

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.

Code Editor
<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"):

Code Editor
<InputMasked asCurrency="EUR" value="1234.50" />

You can also receive a clean number value you can use and send back in again:

Code Editor
<InputMasked
  asCurrency="EUR"
  value="1234.50"
  on_change={({ 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 here also shows how to affect every InputMasked component in your application, by setting these options on the Eufemia Provider.

Code Editor
<Provider
  locale="en-GB"
  InputMasked={{
    currencyMask: {
      decimalLimit: 1, // defaults to 2
    },
  }}
>
  <InputMasked asCurrency="USD" value="1234.567" />
</Provider>
Code Editor
<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:

Code Editor
<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 />)
Date
Code Editor
<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).

Code Editor
<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.

Code Editor
<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

Code Editor
<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

Code Editor
<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

kr
Code Editor
<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

Code Editor
<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.

Code Editor
<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 />)
Date
Code Editor
<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]/],
    },
  ]}
/>