Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement an input with a mask

I would like to implement a mask for a text input field which accepts a date. The masked value should display directly inside of the input.

Something like this:

<input type='text' value='____/__/__'> 

I wrote the mask as a value in that example, but my intent is to allow people to write a date without typing / or - to separate months, years and days. The user should be able to enter numbers into the displayed field, while the mask enforces the format automatically as the user types.

I have seen this behavior on other sites, but I have no idea how it works or how to implement it myself.

like image 377
Stanislas Piotrowski Avatar asked Sep 25 '12 07:09

Stanislas Piotrowski


People also ask

How do you add an input mask in Excel?

Open the table in Design view. Click the field to which you want to add an input mask. In the Field Properties area, click Input Mask under General.

What is input mask in HTML?

An input-mask helps the user with the input by ensuring a predefined format. This can be useful for dates, numerics, phone numbers, ... You can use input-mask with role input , and with core input element.

What is input masking Javascript?

The InputMask control allows you to validate and format user input as it is entered, preventing users from entering invalid data. To use the control, set the mask property to a string that specifies the valid character classes for each input position. The character classes are described in the API documentation.


2 Answers

Input masks can be implemented using a combination of the keyup event, and the HTMLInputElement value, selectionStart, and selectionEnd properties. Here's a very simple implementation which does some of what you want. It's certainly not perfect, but works well enough to demonstrate the principle:

Array.prototype.forEach.call(document.body.querySelectorAll("*[data-mask]"), applyDataMask);    function applyDataMask(field) {      var mask = field.dataset.mask.split('');            // For now, this just strips everything that's not a number      function stripMask(maskedData) {          function isDigit(char) {              return /\d/.test(char);          }          return maskedData.split('').filter(isDigit);      }            // Replace `_` characters with characters from `data`      function applyMask(data) {          return mask.map(function(char) {              if (char != '_') return char;              if (data.length == 0) return char;              return data.shift();          }).join('')      }            function reapplyMask(data) {          return applyMask(stripMask(data));      }            function changed() {             var oldStart = field.selectionStart;          var oldEnd = field.selectionEnd;                    field.value = reapplyMask(field.value);                    field.selectionStart = oldStart;          field.selectionEnd = oldEnd;      }            field.addEventListener('click', changed)      field.addEventListener('keyup', changed)  }
ISO Date: <input type="text" value="____-__-__" data-mask="____-__-__"/><br/>  Telephone: <input type="text" value="(___) ___-____" data-mask="(___) ___-____"/><br/>

(View in JSFiddle)

There are also a number of libraries out there which perform this function. Some examples include:

  • jquery.inputmask
  • MASKED INPUT PLUGIN
  • Politespace (presents an alternative to input masks)
like image 135
Ajedi32 Avatar answered Sep 19 '22 21:09

Ajedi32


A solution that responds to the input event instead of key events (like keyup) will give a smooth experience (no wiggles), and also works when changes are made without the keyboard (context menu, mouse drag, other device...).

The code below will look for input elements that have both a placeholder attribute and a data-slots attribute. The latter should define the character(s) in the placeholder that is/are intended as input slot, for example, "_". An optional data-accept attribute can be provided with a regular expression that defines which characters are allowed in such a slot. The default is \d, i.e. digits.

// This code empowers all input tags having a placeholder and data-slots attribute document.addEventListener('DOMContentLoaded', () => {     for (const el of document.querySelectorAll("[placeholder][data-slots]")) {         const pattern = el.getAttribute("placeholder"),             slots = new Set(el.dataset.slots || "_"),             prev = (j => Array.from(pattern, (c,i) => slots.has(c)? j=i+1: j))(0),             first = [...pattern].findIndex(c => slots.has(c)),             accept = new RegExp(el.dataset.accept || "\\d", "g"),             clean = input => {                 input = input.match(accept) || [];                 return Array.from(pattern, c =>                     input[0] === c || slots.has(c) ? input.shift() || c : c                 );             },             format = () => {                 const [i, j] = [el.selectionStart, el.selectionEnd].map(i => {                     i = clean(el.value.slice(0, i)).findIndex(c => slots.has(c));                     return i<0? prev[prev.length-1]: back? prev[i-1] || first: i;                 });                 el.value = clean(el.value).join``;                 el.setSelectionRange(i, j);                 back = false;             };         let back = false;         el.addEventListener("keydown", (e) => back = e.key === "Backspace");         el.addEventListener("input", format);         el.addEventListener("focus", format);         el.addEventListener("blur", () => el.value === pattern && (el.value=""));     } });
[data-slots] { font-family: monospace }
<label>Date time:      <input placeholder="dd/mm/yyyy hh:mm" data-slots="dmyh"> </label><br> <label>Telephone:     <input placeholder="+1 (___) ___-____" data-slots="_"> </label><br> <label>MAC Address:     <input placeholder="XX:XX:XX:XX:XX:XX" data-slots="X" data-accept="[\dA-H]"> </label><br> <label>Alphanumeric:     <input placeholder="__-__-__-____" data-slots="_" data-accept="\w" size="13"> </label><br> <label>Credit Card:     <input placeholder=".... .... .... ...." data-slots="." data-accept="\d" size="19"> </label><br>
like image 33
trincot Avatar answered Sep 21 '22 21:09

trincot