Skip to content

Latest commit

 

History

History

docs

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 


Support

Do you like Maska? Please support me via Boosty.

Live Demo

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>

Install

Via npm

npm i maska

CDN / Global build

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>

CDN / ES modules

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.

Usage

Maska library consists of three main components:

  • Mask class to mask string values
  • MaskInput class to apply Mask processing to <input>
  • vMaska directive to simplify using of library within Vue components

Vanilla JS

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()

Vue

Import vMaska directive and apply it to the input along with data-maska attribite:

Composition API

<script setup>
import { vMaska } from "maska"
</script>

<template>
  <input v-maska data-maska="#-#">
</template>

Options API

<script>
import { vMaska } from "maska"

export default {
  directives: { maska: vMaska }
}
</script>

<template>
  <input v-maska data-maska="#-#">
</template>

Get value

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 result
  • unmasked: string with unmasked result
  • completed: boolean flag indicating that mask is completed

Composition API

<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>

Options API

<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>

Set mask options

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 []:

Composition API

<script setup>
import { reactive } from "vue"
import { vMaska } from "maska"

const options = reactive({
  mask: "#-#",
  eager: true
})
</script>

<template>
  <input v-maska:[options]>
</template>

Options API

<script>
import { vMaska } from "maska"

export default {
  directives: { maska: vMaska },
  data: () => ({
    options: {
      mask: "#-#",
      eager: true
    }
  })
}
</script>

<template>
  <input v-maska:[options]>
</template>

Global registration of directive

Vue 3

import { createApp } from "vue"
import { vMaska } from "maska"

createApp({}).directive("maska", vMaska)

// or in case of CDN load
Vue.createApp({}).directive("maska", Maska.vMaska)

Vue 2

import Vue from "vue"
import { vMaska } from "maska"

Vue.directive("maska", vMaska)

// or in case of CDN load
Vue.directive("maska", Maska.vMaska)

Nuxt 3

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="#-#" />

Options

Mask options

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.

Description

  • mask / data-maska — mask to apply (string, array of strings or function). If you pass empty string or null it will disable a mask
  • tokens / data-maska-tokens — custom tokens object
  • tokensReplace / 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 type 1, eager mask #-# will show 1- and non-eager will show 1
  • reversed / data-maska-reversed — in reversed mode mask will grow backwards, e.g. for numbers

Types

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

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).

Description

  • onMaskacallback on every mask processing
  • preProcesshook before mask processing
  • postProcesshook after mask processing

Types

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)
})

Tokens

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.

Custom tokens

Add custom tokens via data-maska-tokens attribute or by tokens option:

By data-attr

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 token
    • P is pattern in string form
    • M 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.

By option

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() }
  }
})

Token modifiers

Every token can have a modifier, for example:

{
  0: { pattern: /[0-9]/, optional: true },
  9: { pattern: /[0-9]/, repeated: true },
}
  • optional for optional token
  • multiple for token that can match multiple characters till the next token starts
  • repeated 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

Transform tokens

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.

Dynamic masks

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') ? '#-#' : '##-##'
})

Hooks

Use hooks for transforming whole value:

  • preProcess hook called before mask processing
  • postProcess 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)
})

Events

There are two events you can subscribe to get the masking result:

  • maska event
  • input event

They are essentially the same, but the input event could be fired by any input logic, and the maska event is library specific.

Vanilla JS

document.querySelector("input").addEventListener("maska", onMaska)

Vue

<input v-maska data-maska="#-#" @maska="onMaska" />

Both events contains detail property with given structure:

Description

  • masked: masked value
  • unmasked: unmasked value
  • completed: flag that current mask is completed

Types

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:

Vanilla JS

new MaskInput("input", {
  onMaska: (detail: MaskaDetail) => console.log(detail.completed)
})

Vue

<script setup>
const options = {
  onMaska: (detail: MaskaDetail) => console.log(detail.completed)
}
</script>

<template>
  <input v-maska:[options]>
</template>

Programmatic use

You can use mask function programmatically by importing Mask class. There are three methods available:

  • masked(value) returns masked version of given value
  • unmasked(value) returns unmasked version of given value
  • completed(value) returns true 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