Skip to main content
Vuetify0 v1.0 is here
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

createValidation

Per-input validation with reactive rules, async validation, and Standard Schema support.

Edit this page
Report a Bug
Open issues
View on GitHub
Copy Markdown

PreviewIntermediateJun 29, 2026

Usage

Standalone

Create a validation instance with rules. Pass a value source so validate() reads from it automatically:

ts
import { createValidation } from '@vuetify/v0'
import { shallowRef } from 'vue'

const email = shallowRef('')
const validation = createValidation({
  value: email,
  rules: [
    v => !!v || 'Required',
    v => /^.+@\S+\.\S+$/.test(String(v)) || 'Invalid email',
  ],
})

await validation.validate()

console.log(validation.errors.value)    // ['Required', 'Invalid email']
console.log(validation.isValid.value)   // false

validation.reset()

Explicit Value

Pass the value directly to validate() instead of storing a value source:

ts
const validation = createValidation({
  rules: [v => !!v || 'Required'],
})

await validation.validate('')       // validate with empty string
await validation.validate('hello')  // validate with 'hello'

With Rule Aliases

When a rules context is provided via createRulesPlugin or createRulesContext, alias strings resolve automatically:

ts
const validation = createValidation({
  rules: ['required', 'slug'],
})

With Standard Schema

Any Standard Schema↗︎-compliant library works without an adapter — pass the schema object directly and it’s auto-detected:

zod
import { z } from 'zod'

const validation = createValidation({
  rules: [z.coerce.number().int().min(18, 'Must be 18+')],
})

Dynamic Rules

Register rules individually after creation:

ts
const validation = createValidation()

validation.register(v => !!v || 'Required')
validation.register(v => /^.+@\S+\.\S+$/.test(String(v)) || 'Invalid email')

Use onboard() to register multiple rules at once:

ts
validation.onboard([
  v => !!v || 'Required',
  v => v.length >= 8 || 'Min 8 characters',
  v => /[A-Z]/.test(String(v)) || 'Must contain uppercase',
])

Enabling and Disabling Rules

Each rule is a ticket with selection methods from createGroup. The enroll option (default true) controls whether newly registered rules are active immediately. Set enroll: false to register rules in an inactive state:

ts
const validation = createValidation({
  rules: [
    v => !!v || 'Required',
    v => /^.+@\S+\.\S+$/.test(String(v)) || 'Invalid email',
  ],
})

// Disable the email format rule
const [, format] = [...validation.values()]
format.unselect()

await validation.validate('')
// Only 'Required' runs — format rule is inactive

// Re-enable it
format.select()

Silent Validation

Check validity without updating the UI:

ts
const valid = await validation.validate('', true) // silent = true
// validation.errors.value is unchanged
// validation.isValid.value is unchanged

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:

vue
<script setup lang="ts">
  import { createValidation } from '@vuetify/v0'
  import { shallowRef } from 'vue'

  // Parent provides form context via createFormContext or createFormPlugin
  // This validation auto-registers with it
  const email = shallowRef('')
  const validation = createValidation({
    value: email,
    rules: ['required', 'email'],
  })
</script>

Architecture

createValidation extends createGroup with per-input validation state. Each ticket is a rule. When a parent form context exists, it auto-registers:

Validation Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

Validation Architecture

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.

Reactivity

Context-level state is fully reactive. Rule tickets inherit selection reactivity from createGroup.

Property/MethodReactiveNotes
errorsShallowRef array of error strings
isValidShallowRef (null/true/false)
isValidatingShallowRef boolean
selectedIdsReactive Set of active rule IDs
ticket.isSelectedRef boolean per rule

Examples

Standalone Field Validation

A “build your own field” example that wires createValidation straight to a plain input — no Input component, no parent form. The composable owns the email value as the validation source (value: email), mixes two synchronous rules (required, format) with one async rule that simulates a 700 ms availability check, and exposes a derived status so the UI never has to read the tri-state isValid directly. All active rules run concurrently, and the async availability rule guards itself on sync validity — re-checking required and format before awaiting — so the network call only fires for well-formed input.

Validation is driven on blur rather than on every keystroke: onBlur() flips a touched flag and calls validate(), while a watch on the value resets the result the moment the user edits a field they have already checked. isValidating powers the pending spinner and errors renders the message list, all settling in a single tick thanks to the composable’s generation-based race safety — a second blur while a check is pending discards the stale result. The state panel underneath surfaces status, isValid, isValidating, touched, and the error count live so the policy is observable.

Reach for this pattern when you need validation on a control the Input component does not cover, or when validation has to coordinate with surrounding state you already own. For the batteries-included field that integrates the same engine, see createInput; to aggregate many fields behind one submit button, see createForm; for alias-based rule registration, see useRules.

FileRole
useEmailField.tsOwns the value, the createValidation instance (sync + async rules), the blur handler, and a derived status
EmailField.vuePresentational field — renders the input, pending spinner, availability badge, and error list
email-field.vueEntry — wires the composable to the field and shows a live validation-state panel

Validation State

status: idle

isValid: null

isValidating: false

touched: false

errors: 0

Validation runs on blur. Try "jane@example.com" (registered) or "you@example.com" (available).

FAQ

Discord
Need help? Join our community for support and discussions ↗

API Reference

The following API details are for the createValidation composable.
Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/