Skip to content

Description

The InputMasked component uses the basic Input component, but with some additional masking functionality.

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 (as_currency or as_number).

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
  mask_options={{
    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:

  • as_currency="EUR"
  • as_number={true}

You can still send in custom mask parameters to currency_mask={{ ... }} or number_mask={{ ... }}. But you can also make use of mask_options={{ ... }} and just send in your extra options in there.

More details in the examples above.

Clean number values

If you use as_currency or as_number you have to always send in in a clean number without any mask (value="1234.50"):

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

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

Code Editor
<InputMasked
  as_currency="EUR"
  value="1234.50"
  on_change={({ numberValue }) => {
    console.log(numberValue) // type of float
  }}
/>

Decimals

  • number_mask will default to no decimals
  • currency_mask will default to no decimals
  • as_number will default to no decimals
  • as_currency will default to 2 decimals

You can change the number of decimals by sending in options to the currency_mask, number_mask, or mask_options (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={{
    currency_mask: {
      decimalLimit: 1, // defaults to 2
    },
  }}
>
  <InputMasked as_currency="USD" value="1234.567" />
</Provider>
Code Editor
<Provider
  locale="en-GB"
  InputMasked={{
    number_mask: {
      decimalLimit: 2, // defaults to no decimals
    },
  }}
>
  <InputMasked as_number value="1234.567" />
</Provider>

To remove a decimal limit, you can send in null and allow decimals with allowDecimal:

Code Editor
<InputMasked
  as_number
  mask_options={{
    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/src/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 as_number or as_percent (and as_currency see below) it will create a mask for you and inherit the locale from the Eufemia Provider, if the locale prop is not given.

You can still define extra mask parameters with number_mask or mask_options, as the second input example shows (e.g. decimalLimit).

Code Editor
<Provider
  formElement={{
    label_direction: 'vertical',
  }}
>
  <Flex.Vertical>
    <InputMasked
      label="Number"
      as_number
      mask_options={{
        allowNegative: false,
      }}
      value="1234.50"
      on_change={({ numberValue }) => {
        console.log(numberValue)
      }}
    />
    <InputMasked
      label="Number (decimal limit)"
      as_number
      number_mask={{
        decimalLimit: 2,
      }}
      value="1234.016"
      on_change={({ numberValue }) => {
        console.log(numberValue)
      }}
    />
    <InputMasked
      label="Percentage"
      as_percent
      number_mask={{
        decimalLimit: 1,
      }}
      value="1234.016"
      on_change={({ numberValue }) => {
        console.log(numberValue)
      }}
    />
  </Flex.Vertical>
</Provider>

Locale based as_currency

When you use as_currency it will create a mask for you and inherit the locale from the Eufemia Provider, if the locale prop is not given.

Code Editor
<Provider
  formElement={{
    label_direction: 'vertical',
  }}
>
  <Flex.Vertical>
    <InputMasked
      label="Currency"
      as_currency="EUR"
      value="1234.50"
      on_change={({ numberValue }) => {
        console.log(numberValue)
      }}
    />
    <Provider
      locale="en-GB"
      InputMasked={{
        currency_mask: {
          decimalLimit: 3,
        },
      }}
    >
      <InputMasked
        label="Currency"
        as_currency="USD"
        value="1234.567"
        on_change={({ numberValue }) => {
          console.log(numberValue)
        }}
      />
    </Provider>
  </Flex.Vertical>
</Provider>

Define the currency_mask manually

Code Editor
<Provider
  formElement={{
    label_direction: 'vertical',
  }}
>
  <Flex.Vertical>
    <InputMasked
      label="Left aligned (default)"
      show_mask
      currency_mask="kr"
      on_change={({ numberValue }) => {
        console.log(numberValue)
      }}
    />
    <InputMasked
      label="Right aligned"
      show_mask
      currency_mask={{
        currency: 'NOK',
      }}
      align="right"
      on_change={({ numberValue }) => {
        console.log(numberValue)
      }}
    />
  </Flex.Vertical>
</Provider>

Customize the number mask

Code Editor
<InputMasked
  label="Masked amount"
  show_mask
  number_mask={{
    suffix: ' kr',
    allowDecimal: true,
  }}
  placeholder_char={null}
  on_change={({ numberValue }) => {
    console.log(numberValue)
  }}
/>

Using the number_mask with a combined suffix

kr
Code Editor
<InputMasked
  label="Masked input"
  value="1000000"
  number_mask={{
    suffix: ',-',
    allowDecimal: false,
  }}
  suffix="kr"
  on_change={({ numberValue }) => {
    console.log(parseInt(numberValue || 0, 10))
  }}
/>

Using the number_mask and a prefix

Code Editor
<InputMasked
  label="Masked input"
  number_mask={{
    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 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/,
  ]}
  show_mask
  placeholder_char="_"
  keep_char_positions
  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/src/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]/],
    },
  ]}
/>