Input Masks

Maskito patterns, numbers, currency, dates, times, and custom input processing.

Basic example

Maskito adds input masks to your existing Material text fields. Type, paste, select, and delete text: the input keeps its configured shape while retaining native labels, keyboard interaction, and form submission.

Loading input masks…

Fixed patterns

Use # for a digit, A for an ASCII letter, and * for a letter or digit. Other characters are inserted as literals. Escape a token with a backslash when it should be literal.

Format: +33 6 12 34 56 78
Two letters + four digits; converted to uppercase.
<div class="input-field outlined">
  <input id="phone" type="tel" inputmode="tel" placeholder=" "
         data-maskito="pattern" data-maskito-pattern="+33 # ## ## ## ##">
  <label for="phone">Phone</label>
</div>

The shorthand is provided by kmaterialize. You can also pass Maskito’s native regex, array, or function masks through maskOptions.mask.

Setup

Start with the kmaterialize CSS and JavaScript from Getting started, then follow the component setup below.

Maskito reuses the existing Material text-field styles. No extra stylesheet is required.

npm install kmaterialize @maskito/core @maskito/kit

Core is required for all masks. Kit is an optional addition for number, date, and time presets.

import { MaskitoInput } from 'kmaterialize';

const field = MaskitoInput.init(input, { pattern: 'AA-####' });
await field.ready;

await field.setValue('AB1234'); // Formats and emits input.
console.log(field.getValue()); // 'AB-1234'

input.value = 'CD5678';
await field.refresh(); // Formats without emitting input.

field.destroy(); // Removes mask listeners; keeps the input and its value.

M.AutoInit() recognizes input[data-maskito]. Add no-autoinit for explicit initialization. Use data-maskito-pattern for shorthand patterns and data-maskito-options for JSON-serializable options:

<input type="text" inputmode="decimal" data-maskito="number"
       data-maskito-options='{"number":{"maximumFractionDigits":2,"postfix":" €"}}'>
<script>M.AutoInit();</script>

Examples and variants

Numbers, currency, and percentages

The number preset supports grouping, decimal separators, fraction digits, bounds, and affixes. Keep type="text" and use inputmode="decimal" to request a decimal keyboard.

0–1,000,000 · two decimal places
0–100 · one optional decimal
const budget = MaskitoInput.init(input, {
  preset: 'number',
  number: {
    min: 0,
    max: 1000000,
    maximumFractionDigits: 2,
    minimumFractionDigits: 2,
    decimalSeparator: ',',
    thousandSeparator: ' ',
    postfix: ' €'
  }
});
await budget.ready;
Number optionUse
localeDerive locale-specific number formatting. Explicit separator settings take precedence.
decimalSeparator / thousandSeparatorChoose decimal and grouping characters.
minimumFractionDigits / maximumFractionDigitsControl decimal padding and precision.
min / maxConstrain the numeric value.
prefix / postfixAdd a currency symbol, percentage sign, or unit.
minusSign / negativePatternCustomize negative-value presentation.

Date and time

Date and time presets understand their segments. These are text inputs; their stored values remain formatted strings.

DD/MM/YYYY · between 2020 and 2030
HH:MM · Arrow Up/Down adjusts the active segment
MaskitoInput.init(dateInput, {
  preset: 'date',
  date: {
    mode: 'dd/mm/yyyy',
    separator: '/',
    min: new Date(2020, 0, 1),
    max: new Date(2030, 11, 31)
  }
});

MaskitoInput.init(timeInput, {
  preset: 'time',
  time: { mode: 'HH:MM', step: 1 }
});

Date options include mode, separator, locale, and native Date bounds. Time options include mode, separators, dayPeriod, segment bounds, and arrow-key step. Use JavaScript options for Date objects.

Shift or replace

Place the cursor in the middle and type a digit. Shift moves the following digits; replace overwrites the digit at the cursor.

MaskitoInput.init(input, {
  pattern: '######',
  maskOptions: { overwriteMode: 'replace' } // Or 'shift'.
});

Custom masks and processing

A native regular-expression mask
MaskitoInput.init(input, {
  maskOptions: { mask: /^\d{0,6}$/ }
});

A regex mask must accept intermediate values, including an empty string. An array mask mixes fixed characters and per-character regexes. A function mask can choose a mask from the current value and selection.

// Project-code example: normalize letters after masking.
MaskitoInput.init(input, {
  pattern: 'AA-####',
  maskOptions: {
    postprocessors: [({ value, selection }) => ({
      value: value.toUpperCase(),
      selection
    })]
  }
});
Core optionPurpose
maskA regex, array, or function defining allowed input.
overwriteModeshift, replace, or a function choosing between them.
preprocessorsNormalize incoming text before the mask runs.
postprocessorsAdjust the masked value and selection afterward.
pluginsAdd lifecycle-managed behavior such as a change-event plugin.
import { maskitoChangeEventPlugin } from '@maskito/core';

MaskitoInput.init(input, {
  pattern: '####',
  maskOptions: { plugins: [maskitoChangeEventPlugin()] }
});

Custom preprocessors run before preset preprocessors, and custom postprocessors run after preset postprocessors. Plugins are combined. Supplying maskOptions.mask replaces the preset with your custom mask.

OTP / PIN slots with a mask

OtpInput uses the same Maskito engine with individual Material slots. Try pasting fx2048: two letters, a fixed hyphen, and four digits. See the OTP / PIN Input page for configurable length, hidden PINs, grouping, and validation.

Pattern AA-####. Letters are converted to uppercase.

Enter two letters and four digits.

<div class="input-field outlined">
  <input id="access-code" type="text" placeholder=" " data-otp
         data-otp-pattern="AA-####" aria-describedby="access-help">
  <label for="access-code">Access code</label>
  <span id="access-help" class="supporting-text">Two letters and four digits.</span>
</div>
import { OtpInput } from 'kmaterialize';
const code = OtpInput.init(input, {
  pattern: 'AA-####',
  maskOptions: {
    postprocessors: [({ value, selection }) => ({
      value: value.toUpperCase(), selection
    })]
  }
});
await code.ready;
await code.setValue('fx2048');
code.getValue();         // "FX-2048"
code.getUnmaskedValue(); // "FX2048"

For digits only, use { length: 6 }. Do not attach a second MaskitoInput to an OTP field; OtpInput manages its mask. AutoInit keeps the two initializers separate.

Validation

Masks control formatting; they do not replace validation. Use required for an empty value and a complete-value pattern or application check for a partial entry.

These previews keep their error state visible. In your form, show errors after checking a field or submitting, then clear them when the value is valid.

For text fields, use .input-field.error, aria-invalid="true", and a message linked with aria-describedby. Remove the error state when resolved. Use aria-live="polite" for messages updated dynamically.

Required
Enter a reference code.
Incomplete format
Complete the code: two letters and four digits.
<div class="input-field outlined error">
    <input id="validation-mask" type="text" data-maskito="pattern" data-maskito-pattern="AA-####" required placeholder=" " value="" aria-invalid="true" aria-describedby="validation-mask-error">
    <label for="validation-mask">Reference code</label>
    <span id="validation-mask-error" class="supporting-text"><i class="material-icons" aria-hidden="true">error</i> Enter a reference code.</span>
</div>

<div class="input-field error">
    <input id="validation-mask-incomplete" type="text" data-maskito="pattern" data-maskito-pattern="AA-####" pattern="[A-Za-z]{2}-[0-9]{4}" placeholder=" " value="FX-12" aria-invalid="true" aria-describedby="validation-mask-incomplete-error">
    <label for="validation-mask-incomplete">Reference code</label>
    <span id="validation-mask-incomplete-error" class="supporting-text"><i class="material-icons" aria-hidden="true">error</i> Complete the code: two letters and four digits.</span>
</div>

Reference

Form values and validation

Submit to inspect the native form strings and parsed values.

The native input contains the formatted string, including separators and affixes. Parse numbers, dates, and times with the corresponding kit helper, using the same separators and affixes as the mask:

import { maskitoParseNumber, maskitoParseDate, maskitoParseTime } from '@maskito/kit';

const amount = maskitoParseNumber(input.value, {
  decimalSeparator: ',', thousandSeparator: ' ', postfix: ' €'
});
const date = maskitoParseDate(dateInput.value, { mode: 'dd/mm/yyyy', separator: '/' });
const milliseconds = maskitoParseTime(timeInput.value, { mode: 'HH:MM' });

Masks guide editing; use required, pattern, or application validation to require a complete value. The project-code demo uses pattern="[A-Z]{2}-[0-9]{4}". Native disabled and read-only states still apply.

Supported inputs and lifecycle

Use JavaScript for regexes, functions, and Date objects. Supported input types are text, tel, search, url, and password. Use inputmode rather than type="number" for formatted numbers.

Initialization normalizes the existing value. Form reset reapplies the mask to the default value. Reinitialization replaces the previous instance. Choose one masking engine per input; the existing NumberInput feature continues to use IMask.

Further reference: Maskito core concepts and Maskito kit. TypeScript options are exported as MaskitoInputOptions.