Custom Mask Directive
The v-mask
directive use to mask input value.
Usage
v-mask
will automatically format the input value based on the provided mask.
Select a mask from the dropdown
View Code
vue
<script setup>
import { ref, watch } from "vue";
const mask = ref("###");
const maskPatterns = [
"###-###-####",
"###.###.####",
"### ### ####",
"###",
"@@@@@-###",
"###-###-###",
"###.###",
"(###) ###-####",
];
const inp = ref("");
watch(mask, () => {
inp.value = "";
});
</script>
<template>
<div class="w-full p-5 bg-zinc-100 dark:bg-zinc-800 rounded-2xl space-y-3">
<p>
<code>v-mask</code> will automatically format the input value based on the
provided mask.
</p>
<div>
<p class="text-sm text-gray-500 dark:text-gray-400">
Select a mask from the dropdown
</p>
<select
class="w-full h-10 ring-[1px] ring-zinc-600 bg-zinc-50 dark:bg-zinc-700 resize-none outline-none rounded-xl p-2"
v-model="mask"
>
<option v-for="pattern in maskPatterns" :key="pattern" :value="pattern">
{{ pattern }}
</option>
</select>
</div>
<input
v-custom-mask="mask"
placeholder="Mask"
v-model="inp"
:style="[
mask === 'hex' && inp.length === 7
? `border: 1px solid ${inp}`
: 'border: 1px solid #4f46e5',
]"
class="w-full h-10 bg-zinc-50 dark:bg-zinc-700 resize-none outline-none rounded-xl p-2"
/>
</div>
</template>
<style scoped></style>
Arguments
The v-mask
directive does not accept any arguments.
Modifiers
The v-mask
directive does not accept any modifiers.
Source Code
js
const setMaxLength = (el, length) => {
el.setAttribute("maxlength", length);
};
function applyMask(el, value) {
let mask = el.getAttribute("mask-data");
setMaxLength(el, mask.length);
let maskedValue = "";
let maskArr = mask.split("");
let valueArr = value.split("");
let maskedArr = [];
for (let i = 0; i < maskArr.length; i++) {
const currentMaskChar = maskArr[i];
const currentValueChar = valueArr[i];
if (currentValueChar === undefined) {
break;
} else if (currentMaskChar === "@") {
if (/^[a-zA-Z]$/.test(currentValueChar)) {
maskedArr.push(currentValueChar);
// watch for the next mask char, if not @ or #, add it to the masked value
if (i + 1 < maskArr.length) {
const nextMaskChar = maskArr[i + 1];
if (nextMaskChar !== "@" && nextMaskChar !== "#") {
maskedArr.push(nextMaskChar);
i++;
}
}
}
} else if (currentMaskChar === "#") {
if (/^\d$/.test(currentValueChar)) {
maskedArr.push(currentValueChar);
// watch for the next mask char, if not @ or #, add it to the masked value
if (i + 1 < maskArr.length) {
const nextMaskChar = maskArr[i + 1];
if (nextMaskChar !== "@" && nextMaskChar !== "#") {
maskedArr.push(nextMaskChar);
i++;
}
}
}
} else {
maskedArr.push(currentMaskChar);
}
}
maskedValue = maskedArr.join("");
return maskedValue;
}
function custom(el, binding, event) {
if (!el || !binding || !binding.value) {
return;
}
const mask = binding.value;
if (typeof mask !== "string") {
console.error("Invalid mask format");
return;
}
function applyMaskOnInput() {
let value = el.value;
// Check if there is an existing value before applying the mask
if (value) {
let maskedValue = applyMask(el, value, event);
el.value = maskedValue;
}
}
// Apply the mask on input
el.addEventListener("input", applyMaskOnInput);
}
export const vCustomMask = {
mounted(el, binding) {
el.setAttribute("mask-data", binding.value);
el.addEventListener("input", () => {
// check the first value matches the mask, if not then remove it
let maskVal = el.getAttribute("mask-data");
let maskArr = maskVal.split("");
let valueArr = el.value.split("");
if (maskArr[0] === "@") {
if (!/^[a-zA-Z]$/.test(valueArr[0])) {
el.value = "";
}
} else if (maskArr[0] === "#") {
if (!/^\d$/.test(valueArr[0])) {
el.value = "";
}
}
custom(el, binding);
});
},
updated(el, binding) {
if (binding.value !== binding.oldValue) {
el.setAttribute("mask-data", binding.value);
let mask = binding.value;
if (mask[0] != "#" && mask[0] != "@") {
el.value = mask[0];
}
}
el.addEventListener("input", () => {
custom(el, binding);
});
},
};