Guide
Getting started
npm install @devix-labs/masked-input
import { createMaskedInput } from '@devix-labs/masked-input';
createMaskedInput(document.querySelector('#cnic'), { mask: 'cnic' });
<script type="module" src="https://devix.pk/cdn/oss/masked-input@1.0.0/masked-input.min.js"></script>
<dx-masked-input mask="emirates-id" name="eid"></dx-masked-input>
The stylesheet is optional. A mask only touches the value, so a field you have
already styled needs nothing from us; import @devix-labs/masked-input/styles.css
only if you want the default look.
Why the caret does not jump
This is the bug every mask library has, so it is worth saying how this one avoids it rather than claiming it is careful.
The state kept here is the raw string — only the characters you actually typed, with no separators in it. The text in the field is derived from that. The caret is not stored as an offset into the field; it is stored as "after the nth raw character".
So when the field is re-rendered, the caret is put back after that same character. There is no arithmetic to get wrong, because nothing needs to be adjusted: the thing the caret is pinned to did not move.
Type into the middle of a half-filled CNIC and the caret stays where you are typing. Paste over a selection and it lands at the end of what you pasted.
The value you store is not the value you see
const cnic = createMaskedInput(field, { mask: 'cnic' });
cnic.getValue(); // '42101-1234567-1' — what the user sees
cnic.getRaw(); // '4210112345671' — what you store
And if you are not using JavaScript at all, you still get the clean one. The
widget moves the field's name onto a hidden input carrying the raw value, so a
plain form post sends cnic=4210112345671 with nothing else from you:
<form method="post">
<input name="cnic" id="cnic">
</form>
Pass postRaw: false to turn that off, or rawName to post both.
Patterns
0 or 9 |
a digit |
a |
a letter |
A |
a letter, upper-cased |
* |
a letter or a digit |
\ |
escapes the next character |
| anything else | a literal, written for you |
createMaskedInput(field, { mask: '0000 0000 0000 0000' }); // a card
createMaskedInput(field, { mask: 'AA00 0000' }); // a sort code
createMaskedInput(field, { mask: '\\#000' }); // a literal hash
Your own character classes
createMaskedInput(field, {
mask: { pattern: 'HH:HH:HH:HH:HH:HH', tokens: { H: /[0-9A-Fa-f]/ }, transform: 'upper' },
});
Any regular expression, under any letter. Three fixed classes is not a language.
Presets
Named, so you do not have to remember the grouping — and taken from the same numbers Devix Validators checks, so the mask and the rule cannot disagree.
createMaskedInput(field, { mask: 'emirates-id' });
cnic · ntn · emirates-id · uae-trn · saudi-id · saudi-vat ·
qatar-id · bahrain-cpr · pan · gstin · card · card-amex · expiry ·
cvc · cvc-4 · iban · date · date-iso · time · time-seconds · mac ·
hex
Showing the shape before it is filled
By default the field is empty when it is empty, and separators appear as you reach them. If the user cannot be expected to know the shape, show it:
createMaskedInput(field, {
mask: { pattern: '00/00/0000', lazy: false, placeholderChar: '_' },
});
// __/__/____
Where to go next
- Options and methods — everything the widget takes.
- React, Vue, Svelte and a plain page.
- Amounts are a different problem — grouping separators move as you type and digits fill from the right. That is Devix Amount Input, over this same core.