Do you like Maska? Please support me via Boosty.
Here are several examples of basic masks that you could create with Maska. This demo is interactive: feel free to edit the examples.
<script src="dist/demo.js"></script>npm i maska
You can use Maska directly from CDN with simple script tag.
Library API will be exposed on the global Maska
object:
<script src="https://cdn.jsdelivr.net/npm/maska@2/dist/maska.umd.js"></script>
<script>
const { Mask, MaskInput, vMaska } = Maska
new MaskInput("[data-maska]") // for masked input
const mask = new Mask({ mask: "#-#" }) // for programmatic use
Vue.createApp({ directives: { maska: vMaska }}).mount('#app') // Vue directive
</script>
For modern browsers you can use ES modules build with (optional) import maps:
<script type="importmap">
{
"imports": {
"maska": "https://cdn.jsdelivr.net/npm/maska@2/dist/maska.js"
}
}
</script>
<script type="module">
import { Mask, MaskInput, vMaska } from 'maska'
new MaskInput("[data-maska]") // for masked input
const mask = new Mask({ mask: "#-#" }) // for programmatic use
Vue.createApp({ directives: { maska: vMaska }}).mount('#app') // Vue directive
</script>
Notice that we are using <script type="module">
in this case.
Maska library consists of three main components:
Mask
class to mask string valuesMaskInput
class to applyMask
processing to<input>
vMaska
directive to simplify using of library within Vue components
Start with simple input element and data-maska
attribute:
<input data-maska="#-#">
Then import and init MaskInput
, passing input element(s) or querySelector
expression as first argument:
import { MaskInput } from "maska"
new MaskInput("[data-maska]")
Usually you set mask via data-maska
attribute. But you can pass mask and other options via second argument (it will be a default options that can be overriden by data-maska-
attributes):
new MaskInput("input", { mask: "#-#" })
To destroy mask use destroy()
method:
const mask = new MaskInput(...)
mask.destroy()
Import vMaska
directive and apply it to the input along with data-maska
attribite:
<script setup>
import { vMaska } from "maska"
</script>
<template>
<input v-maska data-maska="#-#">
</template>
<script>
import { vMaska } from "maska"
export default {
directives: { maska: vMaska }
}
</script>
<template>
<input v-maska data-maska="#-#">
</template>
To get masked value you can use standard v-model
directive.
But if you want to access an unmasked (raw) value, you can pass a variable as v-maska
directive value.
This variable should be a reactive object that will contains three fields after mask processing:
masked
: string with masked resultunmasked
: string with unmasked resultcompleted
: boolean flag indicating that mask is completed
<script setup>
import { reactive, ref } from "vue"
import { vMaska } from "maska"
const maskedValue = ref('')
const bindedObject = reactive({})
</script>
<template>
<input v-maska="bindedObject" v-model="maskedValue">
Masked value: {{ maskedValue }} or {{ bindedObject.masked }}
Unmasked value: {{ bindedObject.unmasked }}
<span v-if="bindedObject.completed">✅ Mask completed</span>
</template>
<script>
import { vMaska } from "maska"
export default {
directives: { maska: vMaska },
data: () => ({
maskedValue: "",
bindedObject: {
masked: "",
unmasked: "",
completed: false
}
})
}
</script>
<template>
<input v-maska="bindedObject" v-model="maskedValue">
Masked value: {{ maskedValue }} or {{ bindedObject.masked }}
Unmasked value: {{ bindedObject.unmasked }}
<span v-if="bindedObject.completed">✅ Mask completed</span>
</template>
To set default options for the mask you could use directive argument (part after v-maska:
). It can be plain or reactive object and should be wrapped in []
:
<script setup>
import { reactive } from "vue"
import { vMaska } from "maska"
const options = reactive({
mask: "#-#",
eager: true
})
</script>
<template>
<input v-maska:[options]>
</template>
<script>
import { vMaska } from "maska"
export default {
directives: { maska: vMaska },
data: () => ({
options: {
mask: "#-#",
eager: true
}
})
}
</script>
<template>
<input v-maska:[options]>
</template>
import { createApp } from "vue"
import { vMaska } from "maska"
createApp({}).directive("maska", vMaska)
// or in case of CDN load
Vue.createApp({}).directive("maska", Maska.vMaska)
import Vue from "vue"
import { vMaska } from "maska"
Vue.directive("maska", vMaska)
// or in case of CDN load
Vue.directive("maska", Maska.vMaska)
To use Maska in Nuxt 3 you can make a simple plugin. Create file maska.ts
in plugins
folder:
import { vMaska } from "maska"
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive("maska", vMaska)
})
Now you can use v-maska
directive in your app:
<input v-model="value" v-maska data-maska="#-#" />
Every option of Mask
class can be set via data-maska-
attributes or by passing on init.
Options passed on init will be used as defaults and could be overriden by data-maska-
attributes.
mask / data-maska
— mask to apply (string, array of strings or function). If you pass empty string ornull
it will disable a masktokens / data-maska-tokens
— custom tokens objecttokensReplace / data-maska-tokens-replace
— if custom tokens should replace default tokens (if not set, they will merge)eager / data-maska-eager
— eager mode will show static characters before you type them, e.g. when you type1
, eager mask#-#
will show1-
and non-eager will show1
reversed / data-maska-reversed
— in reversed mode mask will grow backwards, e.g. for numbers
interface MaskOptions {
mask?: MaskType
tokens?: MaskTokens
tokensReplace?: boolean
eager?: boolean
reversed?: boolean
}
<input data-maska="A-A" data-maska-tokens="A:[A-Z]" data-maska-eager>
MaskInput
options could be set only by passing second argument on init.
Along with MaskInput
options you could pass any Mask
options as well (or set them via data-maska-
attributes).
onMaska
— callback on every mask processingpreProcess
— hook before mask processingpostProcess
— hook after mask processing
interface MaskInputOptions extends MaskOptions {
onMaska?: (detail: MaskaDetail) => void
preProcess?: (value: string) => string
postProcess?: (value: string) => string
}
new MaskInput("input", {
mask: "#-#",
reversed: true,
onMaska: (detail: MaskaDetail) => console.log(detail.completed)
})
There are 3 tokens defined by default:
{
'#': { pattern: /[0-9]/ }, // digits
'@': { pattern: /[a-zA-Z]/ }, // letters
'*': { pattern: /[a-zA-Z0-9]/ }, // letters & digits
}
?> Use !
before token to escape symbol. For example !#
will render #
instead of a digit.
Add custom tokens via data-maska-tokens
attribute or by tokens
option:
When using data-maska-tokens
, there are two possible formats:
- Full form should be a valid JSON-string (but can use both single and double quotes) with pattern in string format without delimiters
- Simple form should be a string in format:
T:P:M|T:P:M
where:T
is tokenP
is pattern in string formM
is optional modifier (see below)|
is separator for multiple tokens
<input data-maska="Z-Z" data-maska-tokens="{ 'Z': { 'pattern': '[A-Z]' }}">
<input data-maska="Z-Z" data-maska-tokens="Z:[A-Z]">
<input data-maska="Z-z" data-maska-tokens="Z:[A-Z]|z:[a-z]:multiple">
?> You can’t set transform
function for token via data-maska-tokens
.
If you need this, use tokens
option instead.
When using tokens
option, pattern should be a valid regular expression object:
new MaskInput("[data-maska]", {
mask: "A-A",
tokens: {
A: { pattern: /[A-Z]/, transform: (chr: string) => chr.toUpperCase() }
}
})
Every token can have a modifier, for example:
{
0: { pattern: /[0-9]/, optional: true },
9: { pattern: /[0-9]/, repeated: true },
}
optional
for optional tokenmultiple
for token that can match multiple characters till the next token startsrepeated
for tokens that should be repeated. This token will match only one character, but the token itself (or group of such tokens) can be repeated any number of times
Modifier | Example usage | Mask | Tokens |
---|---|---|---|
optional |
IP address | #00.#00.#00.#00 |
0:[0-9]:optional |
multiple |
CARDHOLDER NAME | A A |
A:[A-Z]:multiple |
repeated |
Money (1 234,56) | 9 99#,## reversed |
9:[0-9]:repeated |
For custom tokens you can define transform
function, applied to a character before masking.
For example, transforming letters to uppercase on input:
{
A: { pattern: /[A-Z]/, transform: (chr: string) => chr.toUpperCase() }
}
?> You can also use hooks for transforming whole value before/after masking.
Pass mask
as array or function to make it dynamic:
- With array a suitable mask will be chosen by length (smallest first)
- With function you can select mask with custom logic using value
new MaskInput("input", {
mask: (value: string) => value.startsWith('1') ? '#-#' : '##-##'
})
Use hooks for transforming whole value:
preProcess
hook called before mask processingpostProcess
hook called after mask processing, but before setting input's value
For example, you can use it to check for a maximum length of masked string:
new MaskInput("input", {
postProcess: (value: string) => value.slice(0, 5)
})
There are two events you can subscribe to get the masking result:
maska
eventinput
event
They are essentially the same, but the input
event could be fired by any input logic, and the maska
event is library specific.
document.querySelector("input").addEventListener("maska", onMaska)
<input v-maska data-maska="#-#" @maska="onMaska" />
Both events contains detail
property with given structure:
masked
: masked valueunmasked
: unmasked valuecompleted
: flag that current mask is completed
interface MaskaDetail {
masked: string
unmasked: string
completed: boolean
}
const onMaska = (event: CustomEvent<MaskaDetail>) => {
console.log({
masked: event.detail.masked,
unmasked: event.detail.unmasked,
completed: event.detail.completed
})
}
Alternatively, you can pass callback function directly with MaskInput
option onMaska
:
new MaskInput("input", {
onMaska: (detail: MaskaDetail) => console.log(detail.completed)
})
<script setup>
const options = {
onMaska: (detail: MaskaDetail) => console.log(detail.completed)
}
</script>
<template>
<input v-maska:[options]>
</template>
You can use mask function programmatically by importing Mask
class.
There are three methods available:
masked(value)
returns masked version of given valueunmasked(value)
returns unmasked version of given valuecompleted(value)
returnstrue
if given value makes mask complete
import { Mask } from "maska"
const mask = new Mask({ mask: "#-#" })
mask.masked("12") // = 1-2
mask.unmasked("12") // = 12
mask.completed("12") // = true