createValidation
Per-field validation lifecycle composable. Manages validation state — errors, validity, pristine tracking — for individual fields. Works standalone or auto-registers with a parent createForm.
Usage
Standalone
Create a validation instance and register fields with rules:
import { createValidation } from '@vuetify/v0'
const validation = createValidation()
const email = validation.register({
id: 'email',
value: '',
rules: [
v => !!v || 'Required',
v => /^.+@\S+\.\S+$/.test(String(v)) || 'Invalid email',
],
})
await email.validate()
console.log(email.errors.value) // ['Required']
console.log(email.isValid.value) // false
console.log(email.isPristine.value) // true
email.reset()With Rule Aliases
When a rules context is provided via createRulesPlugin or createRulesContext, alias strings resolve automatically:
import { createValidation } from '@vuetify/v0'
const validation = createValidation()
const name = validation.register({
id: 'name',
value: '',
rules: ['required', 'slug'],
})With Standard Schema
Pass schema objects directly — they’re auto-detected and wrapped:
import { z } from 'zod'
import { createValidation } from '@vuetify/v0'
const validation = createValidation()
const age = validation.register({
id: 'age',
value: '',
rules: [z.coerce.number().int().min(18, 'Must be 18+')],
})Auto-Registration with Forms
When created inside a component with a parent form context, createValidation auto-registers with the form. The form can then coordinate submit and reset across all registered validations. Cleanup happens automatically via onScopeDispose:
<script setup lang="ts">
import { createValidation } from '@vuetify/v0'
// Parent provides form context via createFormContext or createFormPlugin
// This validation auto-registers with it
const validation = createValidation()
const email = validation.register({
id: 'email',
value: '',
rules: ['required', 'email'],
})
</script>Bulk Registration
Use onboard() to register multiple fields at once:
const validation = createValidation()
const fields = validation.onboard([
{ id: 'name', value: '', rules: ['required'] },
{ id: 'email', value: '', rules: ['required', 'email'] },
{ id: 'bio', value: '', rules: [v => String(v).length <= 500 || 'Too long'] },
])Silent Validation
Check validity without updating the UI:
const valid = await email.validate(true) // silent = true
// email.errors.value is unchanged
// email.isValid.value is unchangedArchitecture
createValidation extends createRegistry with per-ticket validation state. When a parent form context exists, it auto-registers like a child component:
Race Safety
Async validation uses a generation counter to prevent stale results. If a newer validation starts before an older one completes, the older result is discarded:
// User types fast — each keystroke triggers validation
email.value = 'a' // generation 1
email.value = 'ab' // generation 2 — generation 1 result discarded
email.value = 'abc' // generation 3 — generation 2 result discarded
// Only generation 3 result is appliedReactivity
Field-level and aggregate state are fully reactive.
| Property/Method | Reactive | Notes |
|---|---|---|
isValid | Computed aggregate from all tickets | |
isValidating | Computed aggregate from all tickets | |
ticket.value | ShallowRef, resets isValid on change | |
ticket.errors | ShallowRef array | |
ticket.isValid | ShallowRef (null/true/false) | |
ticket.isPristine | ShallowRef boolean | |
ticket.isValidating | ShallowRef boolean |
Functions
Options
Properties
isValid
ComputedRef<boolean | null>Aggregate: true if all tickets valid, false if any invalid, null if any unvalidated.
Methods
move
(id: ID, toIndex: number) => E | undefinedSeek for a ticket based on direction and optional predicate
seek
(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefinedon
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidListen for registry events
off
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidStop listening for registry events
emit
<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => voidEmit an event with data
batch
<R>(fn: () => R) => RExecute operations in a batch, deferring cache invalidation and event emission until complete
register
(registration?: Partial<Z>) => Eonboard
(registrations: Partial<Z>[]) => E[]