IMask.js
IMask.js is a robust vanilla JavaScript input mask library that dynamically formats user input in form fields, ensuring data consistency and improving user experience. It supports a wide array of mask types including pattern, number, date, range, enum, and dynamic masks, and allows for custom definitions and repeating blocks. The library is currently in active development, with version 7.6.1 being the latest stable release, featuring frequent minor updates to address bugs and introduce enhancements like autofix options and improved IME support. A key differentiator is its framework-agnostic core, accompanied by dedicated plugins for popular frameworks such as React, Vue, Angular, Svelte, and Solid, enabling consistent masking behavior across various JavaScript ecosystems. It has no external dependencies and is designed for broad browser compatibility.
Common errors
-
IMask is not defined
cause The IMask library script was not loaded or initialized before attempting to use it, or it's not correctly imported in an ESM context.fixEnsure `IMask` is imported as `import IMask from 'imask';` at the top of your module or that the `<script src="https://unpkg.com/imask"></script>` tag is placed before any script attempting to use `IMask` in a global context. -
TypeError: IMask.InputMask is not a constructor
cause This error can occur in specific build environments (e.g., production bundles) where the `InputMask` component might not be correctly exposed or tree-shaken, or when trying to instantiate it directly in a way not intended by the library.fixAlways initialize IMask using the main factory function: `const mask = IMask(element, options);` Do not try to directly construct `IMask.InputMask` or similar internal components. Ensure your bundler is configured correctly if tree-shaking is aggressively removing parts of `imask`. -
Value not updating or mask not applying on component mount (React/Vue)
cause Framework-specific plugins might have nuances. For React hooks (`useIMask`), issues can arise if the `value` prop is not handled correctly, or if `onAccept` is not called as expected. Old versions might not apply the mask on initial value set.fixFor React/Vue plugins, ensure you are on the latest minor version. In `v7.6.0`, `onAccept` is now only called on init if the value changes, which might affect validation logic. Always refer to the specific plugin documentation for correct lifecycle and prop handling. Ensure `ref` is passed correctly in React hooks if needed. -
Copy/paste doesn't work as expected with complex masks (e.g., numbers with separators)
cause IMask's internal handling of pasted input might not correctly interpret non-mask characters or resolve complex formatting variations during paste operations. This is especially noticeable with localized number formats.fixTest copy/paste functionality thoroughly with your specific mask configuration. For number masks, ensure `thousandsSeparator` and `radix` options are correctly set to match expected input formats. Consider implementing a custom `prepare` callback to normalize pasted values if default behavior is insufficient.
Warnings
- breaking Starting from `v7.1.2`, the explicit `esm` part in import paths for specific mask modules can be skipped. This means `import 'imask/esm/masked/number'` should now be `import 'imask/masked/number';`. While the old path might still work due to compatibility, updating is recommended.
- breaking In `v7.1.1`, the `type: "module"` was set for all packages except Angular. This change primarily affects CommonJS environments or older build setups, potentially leading to module resolution issues if not configured correctly for ESM. `v7.2.0` later added a `cjs` build, mitigating some of these issues but requiring awareness.
- gotcha When applying `IMask` to an input element, always use `type="text"`. Other input types (e.g., `type="number"`, `type="tel"`) are not officially supported and may lead to unexpected behavior or conflicts with native browser input handling.
- gotcha For optimal tree-shaking and reduced bundle size, individual mask types (e.g., `Number`, `Date`) should be imported via their specific paths (e.g., `import 'imask/masked/number'`) rather than attempting to destructure them from the main `imask` import. The latter will pull in the entire library.
- gotcha IMask operates by creating an internal 'masked input' layer. Directly manipulating the original HTML input element's properties (like `disabled` state or classes) dynamically via JavaScript or a framework's data binding might not reflect on the visible masked input. Events should also be attached to the `IMask` instance callbacks.
- gotcha Intermediate validation states for complex masks like `Date` or `RegExp` can be tricky. A mask like `/^123$/` will only validate the complete string '123' and prevent any input until it matches perfectly. Always consider intermediate values for masks, otherwise, input might not be possible.
Install
-
npm install imask -
yarn add imask -
pnpm add imask
Imports
- IMask
const IMask = require('imask');import IMask from 'imask';
- Masked options (e.g., Number, Date)
import { Number } from 'imask'; // Number, Date, etc., are not directly exported for tree-shaking import IMask, { Number } from 'imask';import IMask from 'imask'; import 'imask/masked/number'; // for number mask // or specific masks like import 'imask/masked/date'; const element = document.getElementById('my-input'); const mask = IMask(element, { mask: Number }); - IMask.Masked options (e.g., IMask.MaskedPattern)
import { MaskedPattern } from 'imask'; import { MaskedPattern } from 'imask/masked/pattern';import IMask from 'imask'; const patternMasked = IMask.MaskedPattern({ mask: '+{7}(000)000-00-00' });
Quickstart
import IMask from 'imask';
document.addEventListener('DOMContentLoaded', () => {
const phoneInput = document.getElementById('phone-input');
if (phoneInput) {
const phoneMask = IMask(phoneInput, {
mask: '+{7}(000)000-00-00',
lazy: false, // show placeholder from start
placeholderChar: '_'
});
// Example of accessing values
phoneInput.addEventListener('blur', () => {
console.log('Masked Value:', phoneMask.value);
console.log('Unmasked Value:', phoneMask.unmaskedValue);
});
}
const currencyInput = document.getElementById('currency-input');
if (currencyInput) {
const currencyMask = IMask(currencyInput, {
mask: Number,
thousandsSeparator: ' ',
scale: 2, // digits after point
signed: false, // disallow negative
padFractionalZeros: true, // if true, then pads zeros at end to the length of scale
normalizeZeros: true, // appends or removes zeros at the end of the fractional part of a number
mapToRadix: ['.', ','], // to change radix point for `.` or `,` from keyboard
radix: '.', // fractional delimiter
autofix: true // automatically fix incomplete input
});
}
});
// To make this runnable in a browser, you'd need HTML like:
// <input type="text" id="phone-input" placeholder="+7(___)___-__-__">
// <input type="text" id="currency-input" placeholder="0.00">