Lightweight Form Validation and Input Masking/Formatting – Masker.js

Category: Form , Javascript | February 9, 2026
AuthorGrimshire
Last UpdateFebruary 9, 2026
LicenseMIT
Views95 views
Lightweight Form Validation and Input Masking/Formatting – Masker.js

Masker.js is a lightweight, dependency-free JavaScript library that provides declarative input masking and validation for HTML forms.

Features:

  • Input masking for phone numbers across 12 international formats (US, UK, FR, DE, JP, IN, CN, KR, BR, AR, AU, DSN)
  • Date input formatting with both civilian and military date formats
  • Character counting with visible or hidden counters for text areas and input fields
  • Email format validation with faux masking capabilities
  • Number-only input filtering
  • Single-field validation for required fields, date formats, and email addresses
  • Cross-field date range validation for start and end date pairs
  • Custom error messaging through data attributes

How to use it:

1. Download the package and add the script to your HTML file:

<script src="Masker.js"></script>

2. Add the masker attribute to your <input> or <textarea> elements. The value of this attribute is a space-separated list of keywords that define the masks and validation rules.

<!-- A required US phone number input -->
<input type="text" id="phone" masker="phone required" data-format="US" />
<span class="error-msg" data-error-for="phone"></span>
<!-- A date input that must be after 1900 -->
<input type="text" id="birthdate" masker="date 1900" data-format="MDY" />
<span class="error-msg" data-error-for="birthdate"></span>
...

3. Call Masker.init() after the DOM has loaded. This method scans the document for all elements with a [masker] attribute and attaches the necessary event listeners.

document.addEventListener('DOMContentLoaded', () => {
  Masker.init();
});

4. Key Attributes and API:

  • masker="[keywords]": The core attribute. Keywords include char-count, number, phone, email, date, required, begin, end, and more.
  • data-format="[format]": Specifies the format for phones (US, UK, FR, DE, JP, IN, CN, KR, BR, AR, AU, DSN) or dates (MDY, DMY, US-MIL).
  • data-pair="[name]": Links two date inputs (begin and end) together for range validation. This is the magic for start/end date fields.
  • data-errMsg="[message]": Provides a custom error message for a field.
  • data-errMsg-range-start / data-errMsg-range-end: Custom messages specifically for date range validation errors.

5. For situations where you need to run validation programmatically (like before a form submission), you can call the Validator methods directly:

const emailField = document.getElementById('email-address');
const startDateField = document.getElementById('start-date');
const endDateField = document.getElementById('end-date');
// Manually validate a required field
Validator.validateRequired(emailField);
// Manually check a date range
if (!Validator.validateDateRange(startDateField, endDateField)) {
  console.warn('The selected date range is not valid.');
}

6. Full examples:

<h2>Character Counter Masks</h2>
<div class="form-group">
  <label for="notes">Notes (Counter hidden until typing)</label>
  <textarea id="notes" masker="char-count" maxlength="200"></textarea>
  <div class="feedback" data-feedback-for="notes"></div>
</div>
<div class="form-group">
  <label for="bio">Bio (Counter visible and required)</label>
  <textarea id="bio" masker="char-count visible required" maxlength="150"
      data-errMsg="Please provide a short bio."></textarea>
  <div class="feedback" data-feedback-for="bio"></div>
  <span class="error-msg" data-error-for="bio"></span>
</div>
<h2>Number & Phone Masks</h2>
<div class="form-group">
  <label for="account-id">Account ID (Numbers only)</label>
  <input type="text" id="account-id" masker="number" maxlength="8" />
</div>
<div class="form-group">
  <label for="us-phone">US Phone (Required)</label>
  <input type="text" id="us-phone" masker="phone required" data-format="US" />
  <span class="error-msg" data-error-for="us-phone"></span>
</div>
<div class="form-group">
  <label for="uk-phone">UK Phone (Visible Placeholder)</label>
  <input type="text" id="uk-phone" masker="phone visible" data-format="UK" />
</div>
<h2>Email Mask & Validation</h2>
<div class="form-group">
  <label for="email-address">Email Address (Required)</label>
  <input type="email" id="email-address" masker="email required"
      data-errMsg="A valid email address is required." />
  <span class="error-msg" data-error-for="email-address"></span>
</div>
<h2>Single Date & Validation Masks</h2>
<div class="form-group">
  <label for="invalid-date-test">Date (Test invalid month/day)</label>
  <input type="text" id="invalid-date-test" masker="date" data-format="MDY" />
  <span class="error-msg" data-error-for="invalid-date-test"></span>
</div>
<div class="form-group">
  <label for="year-default">Date (Default: No past years)</label>
  <input type="text" id="year-default" masker="date" data-format="MDY" />
  <span class="error-msg" data-error-for="year-default"></span>
</div>
<div class="form-group">
  <label for="year-1900">Date (Since 1900)</label>
  <input type="text" id="year-1900" masker="date 1900" data-format="MDY" />
  <span class="error-msg" data-error-for="year-1900"></span>
</div>
<div class="form-group">
  <label for="year-future">Date (Future years only)</label>
  <input type="text" id="year-future" masker="date future" data-format="MDY" />
  <span class="error-msg" data-error-for="year-future"></span>
</div>
<div class="form-group">
  <label for="year-any">Date (Any year allowed)</label>
  <input type="text" id="year-any" masker="date ancient future" data-format="MDY" />
  <span class="error-msg" data-error-for="year-any"></span>
</div>
<div class="form-group">
  <label for="mil-date">Military Date</label>
  <input type="text" id="mil-date" masker="date" data-format="US-MIL" />
  <span class="error-msg" data-error-for="mil-date"></span>
</div>
<h2>Date Range Validation</h2>
<div class="form-group">
  <label for="start-date">Start Date</label>
  <input type="text" id="start-date" title="Start Date" masker="date begin required" data-format="MDY"
    data-pair="project-dates" />
  <span class="error-msg" data-error-for="start-date"></span>
</div>
<div class="form-group">
  <label for="end-date">End Date</label>
  <input type="text" id="end-date" title="End Date" masker="date end required" data-format="MDY"
    data-pair="project-dates" />
  <span class="error-msg" data-error-for="end-date"></span>
</div>
<div class="form-group">
  <button type="button" onclick="
    const errs = Validator.triggerAllValidations();
    if (errs.length > 0) {
        const errorMessages = errs.map(e => `• ${e.title}: ${e.message}`).join('\n');
        alert('Please correct the following errors:\n\n' + errorMessages);
    } else {
        alert('Form successfully submitted in theory! And passed validation! Huzzah!');
    }
    ">Submit</button>
</div>

Changelog:

02/09/2025

  • v2.1

You Might Be Interested In:


Leave a Reply