Custom Validators

You can easily write custom validators and combine them with builtin ones, as those are just a simple predicate functions.

Simple example

Suppose you want a validator that checks if a string contains the word cool in it. You can write a plain JavaScript function to check that:

const mustBeCool = (value) => value.includes('cool')

The second part is actually applying your validator. You can do it exactly the same way as with builtin ones.

export default {
  data () {
    return {
      myField: 'cool'
    }
  },
  validations () {
    return {
      myField: {
        required, mustBeCool
      }
    }
  }
}

Optional validator

The pattern presented above is often good enough, but this validator will always return false for empty inputs. This is not correct when your input is considered optional. For this reason, Vuelidate provides a req helper, which is a kinda stripped-down version of required validator. You can use it to make your validator behave well in presence of optional fields.

import { helpers } from '@vuelidate/validators'

const mustBeCool = (value) => !helpers.req(value) || value.includes('cool')

export default {
  data () {},
  validations () {
    return {
      myField: {
        mustBeCool
      }
    }
  }
}

Extra parameters

If your validator needs to provide parameters, you can simply create a higher order function that returns the actual validator. This works great for simple validation cases:

import { helpers } from '@vuelidate/validators'

const contains = (param) => (value) =>
  !helpers.req(value) || value.includes(param)

export default {
  data () {},
  validations () {
    return {
      myField: {
        mustBeCool: contains('cool')
      }
    }
  }
}

WARNING

If you need to pass reactive properties, you must use withParams helper, listed in Passing extra reactive properties

Passing extra properties to validators

If you need to attach extra properties to your validation result, to display in error messages for example, you can use the withParams helper. It will attach a $params attribute on your validation result. Let's add a type property, so that we can later retrieve it.

TIP

$params is reactive, which means you could add computed properties, this properties, ref or other, and they will update accordingly.

import { helpers } from '@vuelidate/validators'

const mustBeCool = helpers.withParams(
  { type: 'mustBeCool' },
  (value) => !helpers.req(value) || value.includes('cool')
)

// ...

console.log(this.$v.myField.mustBeCool.$params)
// -> { type: 'mustBeCool' }

Passing extra reactive properties

The same behaviour extends to higher order validators, ones with extra parameters. You just must be careful to wrap the inner function with withParams call, as follows.

import { helpers } from '@vuelidate/validators'

const contains = (param) =>
  helpers.withParams(
    { type: 'contains', value: param },
    (value) => !helpers.req(value) || value.includes(param)
  )

export default {
  validations () {
    return {
      myField: {
        mustBeCool: contains('cool')
      }
    }
  },
  created () {
    console.log(this.$v.myField.mustBeCool.$params)
    // -> { type: 'contains', value: 'cool' }
  }
}

Accessing property parent object

If you need to create a validator, that directly needs access to a sibling property, you can use the second parameter of validators. The second parameter represents the object, surrounding the current property. It works for nested object properties, as well as top level properties, in which case it will just return the entire validated state.

function otherFieldContainsMe (value, siblings) {
  return siblings.other.contains(value)
}

const v$ = useVuelidate({
  foo: { otherFieldContainsMe }
}, {
  foo: 'foo',
  other: 'bar',
})

Accessing component instance from validator

In more complex cases when access to the whole model is necessary, you can make use of the function context (this), or the third parameter, to access any value on your component, this includes computed properties and data properties.

// both equivalent
const otherFieldContainsMe = (value, siblings, vm) => {
  return vm.other.nested.field.contains(value)
}

function otherFieldContainsMe (value) {
  return this.other.nested.field.contains(value)
}

WARNING

When using with Composition API, vm and this may not have your state on initial call. This is because the composition state has not yet been attached to the Vue instance yet. To work around this, you can either use the $lazy option, or use await nextTick() in your validator.

regex based validator

Some validators can be easily expressed as regex. You can use a regex helper to quickly define full-fledged validator of this kind. This already includes handling optional fields and $params.

import { helpers } from 'vuelidate/lib/validators'

const alpha = helpers.regex(/^[a-zA-Z]*$/)

// Also, you can pass multiple regex to validate a value.
const alpha2 = helpers.regex(/^[a-zA-Z]{3}/, /\d/)

Custom error messages

While validators from the @vuelidate/validators package come with basic error messages, you may want to override them or define messages for your own validators. The best way to do this is via the withMessage helper.

withMessage takes message as the first argument, and a validator as the second argument, returning a version of that validator with the customised message.

import { required, helpers } from '@vuelidate/validators'

const validations = {
  name: {
    required: helpers.withMessage('This field cannot be empty', required)
  }
}

$message can also take a function that is reactive to changes in the validator state and model. The $messages function receives an object with the following properties:

Property
$invalidThe valid state of the validator
$modelThe value being validated
$paramsValues of params in any validator created with the withParams helper
$pendingWhether an async validator has resolved yet
import { required, helpers, minLength } from '@vuelidate/validators'

const validations = {
  name: {
    minLength: helpers.withMessage(
      ({
        $pending,
        $invalid,
        $params,
        $model
      }) => `This field has a value of '${$model}' but must have a min length of ${$params.min} so it is ${$invalid ? 'invalid' : 'valid'}`,
      minLength(4)
    )
  }
}

Async validators

Async validators that return a Promise, need to be wrapped in the withAsync helper. This will tell Vuelidate to treat the validator in a special way, tracking pending status, storing response and more.

import { helpers } from '@vuelidate/validators'

const { withAsync } = helpers
export default {
  data () {
    return { foo: '' }
  },
  validations: {
    foo: { asyncValidator: withAsync(asyncValidator) }
  }
}

Async validators with extra reactive dependencies

When your async validator depends internally on other properties, you can pass those as a second parameter to the withAsync helper.

Such scenarios are common, when relying on some reactive data, different from the validated property.

const foo = ref('')

function validator (value) {
  if (foo.value === 'foo') return false
  return value === 'bar'
}

const asyncValidator = withAsync(validator, foo) // here we pass in the `foo` ref as an extra watch target.

const validations = {
  someProperty: { asyncValidator }
}

Watching multiple extra values

You can pass multiple extra dependencies to track, by passing an array of refs to withAsync.

const foo = ref('')
const bar = ref(false)
const validator = () => true

const asyncValidator = withAsync(validator, [foo, bar]) // here we pass in the `foo` and `bar` refs, as extra watch targets.

Passing a reactive property

To pass a reactive property, when using the Options or Composition APis, you can just pass a function returning the correct value, or a computed property, returning that value:

const store = reactive({ foo: '' })

// when using Composition API
const asyncValidator = withAsync(validator, () => store.foo)

// or a computed property
const getter = computed(() => store.foo)
const asyncValidator = withAsync(validator, getter)

// when using Options API
export default {
  validatons () {
    return {
      foo: {
        validator: withAsync(asyncValidator, () => this.store.foo)
      }
    }
  }
}

forEach helper

The forEach helper is added for cases where you might need a very simple collection validation, but don't want to go into defining new components. Please read Validating Collections carefully, before using it.

import { helpers } from '@vuelidate/validators'

const rules = {
  collection: {
    $each: helpers.forEach({
      name: {
        required
      }
    })
  }
}

List of helpers

This table contains all helpers that can be used to help you with writing your own validators. You can import them from validators library

import { helpers } from '@vuelidate/validators'
HelperDescription
withParamsAllows adding $params metadata to your validation function.
withMessageAllows adding custom error messages to built-in or custom validators
withAsyncSpecifies that a validator returns a promise.
forEachHelper to migrate from old $each helper more easily.
reqMinimal version of required validator. Use it to make your validator accept optional fields
lenGet length of any kind value, whatever makes sense in the context. This can mean array length, string length, or number of keys on the object
regexUseful for quick creation of regex based validators.
unwrapExtract a value, from a ref, computed, or reactive property.