inpmask
v1.2.3
Published
Ultra-lightweight input mask library for form fields (~1.2 KB gzipped)
Maintainers
Readme
inpMask.js
Lightweight (~2.4 KB minified / ~1.2 KB gzipped) vanilla JavaScript library for applying real-time input masks and validation to form fields.
No dependencies. Automatic initialization. Modern browsers only (ES6+).
Features
- Auto-initializes on any
<input>withdata-maskattribute - Real-time masking while typing
- Supports fixed characters (separators like -, /, ., etc.)
- Placeholder tokens:
0→ digit (0-9)A→ alphanumeric, case independentX→ alphanumeric, uppercasex→ alphanumeric, lowercaseL→ letter (a-zA-Z)U→ uppercase letteru→ lowercase letter?→ any character.... decimal separator position
- Case conversion support (uppercase/lowercase via token variants)
- Numeric mode with decimal support, fixed precision, min/max range validation
- Automatic maxlength calculation using the
data-masklength - Custom regex check via
data-patwhen leaving the input field - Custom validation functions via
data-chk="functionName" - Visual feedback classes:
.ok,.nok,.no - Right-alignment helper for numeric fields via
.no - Support for SPAs or dynamic content
- Efficient singleton implementation
Install
Via npm (recommended):
npm install inpmaskQuick CDN usage:
<script src="https://cdn.jsdelivr.net/npm/inpmask/dist/inpmask-min.js"></script>Optional: include the example stylesheet for visual feedback:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/inpmask/example/inpmask.css">Or build from source:
npm install
npm test # Run tests
npm run build # Build production bundleUsage
Just add data-mask (and optional attributes) to your inputs — the library handles everything automatically on pageload.
Basic masked input
<input data-mask="000.000.000-00">ISO Date example
<input data-mask="00000?00?00" minlength=8 data-chk="checkISODate" placeholder="YYYY-MM-DD or YYYYMMDD">Numeric with decimals & range
<input data-mask="00000.00" data-min="0" data-max="99999.99" placeholder="Amount">→ Automatically formats to two decimal places on blur
→ Applies .no class for right alignment (see CSS below)
Custom regex pattern
<input data-mask="UU000000" maxlength="10" data-pat="^[A-Z]{2}\d{6,}$" placeholder="Passport style">Custom check function
<input data-mask="XAAAAAAAA" data-pat="^[A-Z]\d{6,}$" data-chk="checkTEST" placeholder="CPF id">Define the function globally:
function checkTEST(value, el, pat) {
// return null or undefined if valid
// return a string (error message) if invalid
const v = value.toUpperCase();
if (pat && !v.match(pat)) return 'Does not match pattern: '+pat;
// ... additional logic ...
if (el && el.value !== v) el.value = v;
return null;
}→ On blur: if the function returns a string → sets custom validity + adds .nok class
→ If valid → adds .ok class
Visual Feedback & Styling
The library adds these classes on blur (and removes them on focus):
ok→ valid & non-empty inputnok→ invalid (failed mask, range, custom check, etc.)no→ formatted numeric field (useful for right alignment)
Example CSS (example/inpmask.css or your own):
input {
padding: 0.5em;
border: 1px solid #ccc;
transition: all 0.2s;
}
input.ok {
border-color: #28a745;
background-color: #e8f5e9;
}
input.nok {
border-color: #dc3545;
background-color: #f8d7da;
}
input.no {
text-align: right;
}API (for SPAs or dynamic content)
// Get the singleton instance
const masker = new inpMask();
// Remove all masks and listeners
masker.destroy();
// Re-scan DOM and re-apply masks
masker.reinit();Attributes Reference
| Attribute | Description | Example |
|-----------------|--------------------------------------------------|-----------------------------|
| data-mask | Main mask pattern | "000.000.000-00" |
| data-pat | Custom regex on exit input field | "^[A-Z]{3}-[0-9]{4}$" |
| data-chk | Global function name for extra validation | "checkIBAN" |
| data-min | Minimum value (numeric mode) | "0" or "0.01" |
| data-max | Maximum value (numeric mode) | "1000" |
Custom Validation Examples
Use the data-chk attribute to call a global validation function on blur.
The function receives (value, element) and should return:
nullorundefined→ valid- a string → error message (sets custom validity +
.nokclass)
1. Brazilian CNPJ
<input data-mask="00.000.000/0000-00" data-chk="checkCNPJ" placeholder="12.345.678/0001-99" maxlength="18"/>function checkCNPJ(value, element) {
let cnpj = value.replace(/\D/g, '');
if (cnpj.length !== 14) return "CNPJ must have exactly 14 digits";
if (/^(\d)\1+$/.test(cnpj)) return "Invalid CNPJ: all digits identical";
let sum = 0;
let weights = [5,4,3,2,9,8,7,6,5,4,3,2];
for (let i = 0; i < 12; i++) sum += parseInt(cnpj[i]) * weights[i];
let mod = sum % 11;
let digit1 = mod < 2 ? 0 : 11 - mod;
if (parseInt(cnpj[12]) !== digit1) return "Invalid CNPJ check digit 1";
sum = 0;
weights = [6,5,4,3,2,9,8,7,6,5,4,3,2];
for (let i = 0; i < 13; i++) sum += parseInt(cnpj[i]) * weights[i];
mod = sum % 11;
let digit2 = mod < 2 ? 0 : 11 - mod;
if (parseInt(cnpj[13]) !== digit2) return "Invalid CNPJ check digit 2";
return null;
}2. Flexible ISO Date (accepts YYYY-MM-DD or YYYYMMDD)
<input data-mask="0000?00?00" minlength="8" data-chk="checkISODate" placeholder="2026-02-24 or 20260224"/>function checkISODate(value, el) {
const digits = value.trim().replace(/\D/g, '');
if (digits.length !== 8) {
return "Date must consist of exactly 8 digits (YYYYMMDD)";
}
const year = parseInt(digits.substring(0, 4), 10);
const month = parseInt(digits.substring(4, 6), 10);
const day = parseInt(digits.substring(6, 8), 10);
if (isNaN(year) || year < 1900 || year > 2100) {
return "Year must be between 1900 and 2100";
}
if (isNaN(month) || month < 1 || month > 12) {
return "Month must be 01–12";
}
if (isNaN(day) || day < 1 || day > 31) {
return "Day must be 01–31";
}
const date = new Date(year, month - 1, day);
if (isNaN(date.getTime()) || date.getFullYear() !== year
|| date.getMonth() !== month - 1 || date.getDate() !== day) {
return "Invalid date";
}
// set the ISO date back as YYYY-MM-DD
if (el) el.value = digits.substring(0,4)+'-'+digits.substring(4,6)+'-'+digits.substring(6,8);
return null;
}3. International Phone (expects leading +, cleans (0), formats nicely, stores E.164)
<input data-mask="+0" minlength="11" maxlength="25" data-chk="checkPhone" placeholder="+31 (0) 10 123 4567" required/>function checkPhone(value, el) {
if (!value.startsWith('+')) return "Phone number must start with +";
const cleaned = value.replace(/[^\d()]/g, '');
const digits = cleaned.replace(/\(\d+\)/, '');
if (digits.length < 9) return "Phone number too short (at least 9 digits after +)";
if (digits.length > 15) return "Phone number too long (maximum 15 digits after +)";
if (digits.startsWith('0')) return "Country code cannot start with 0";
// sets the int.phonenumber back as an E164 number
if (el) el.value = '+' + digits;
return null;
}Notes
- The library works best with default
type="text"inputs (auto-setsinputmodewhen appropriate). - For best UX, combine with the provided CSS classes.
- Focuses on strict enforcement + formatting with custom check functions.
License
MIT (see LICENSE file)
Repository
https://codeberg.org/HansH111/inpmask-js
Enjoy ultra-lightweight input masking!
