Form Validation
The useValidate composable provides declarative, attribute-driven form validation. Chain rules with pipe syntax (required|email|min:3), choose when validation triggers, and customise every error message — all without writing JavaScript.
Required & Email
<form data-vd-validate novalidate>
<div class="vd-form-group">
<label for="name">Full Name</label>
<input type="text" id="name" class="vd-input"
data-vd-rules="required"
data-vd-msg-required="Please enter your name">
</div>
<div class="vd-form-group">
<label for="email">Email</label>
<input type="email" id="email" class="vd-input"
data-vd-rules="required|email">
</div>
<button type="submit" class="vd-btn vd-btn-primary">Submit</button>
</form>Min / Max Length & Number Range
<input class="vd-input"
data-vd-rules="required|min:3|max:20">
<input type="number" class="vd-input"
data-vd-rules="required|number|minVal:18|maxVal:120">Password Match
<input type="password" id="pass" class="vd-input"
data-vd-rules="required|min:8">
<input type="password" class="vd-input"
data-vd-rules="required|match:pass"
data-vd-msg-match="Passwords do not match">Validation Modes & Custom Messages
<!-- Form-level mode: blur -->
<form data-vd-validate data-vd-validate-mode="blur">
<!-- URL with custom message -->
<input class="vd-input"
data-vd-rules="required|url"
data-vd-msg-url="Enter a valid URL">
<!-- Per-field mode override: input -->
<input class="vd-input"
data-vd-rules="required|pattern:^#[0-9a-fA-F]{6}$"
data-vd-validate-mode="input"
data-vd-msg-pattern="Must be a hex color">
</form>Built-in Validation Rules
| Rule | Syntax | Description |
|---|---|---|
required | required | Field must not be empty |
email | email | Must be a valid email address |
url | url | Must be a valid URL |
number | number | Must be a numeric value |
min | min:N | Minimum string length of N characters |
max | max:N | Maximum string length of N characters |
minVal | minVal:N | Numeric value must be ≥ N |
maxVal | maxVal:N | Numeric value must be ≤ N |
pattern | pattern:REGEX | Value must match the given regular expression |
match | match:ID | Value must equal the value of the element with the given id |
API Reference
Wiring
import { ref } from 'vue';
import { useValidate } from "@vanduo-oss/vd3";
const root = ref<HTMLElement | null>(null);
useValidate(root); // wires [data-vd-validate] forms inside root; cleanup on unmountCSS Classes
| Class | Description |
|---|---|
.vd-validate | Optional base class applied to forms for scoped styling |
.is-valid | Added to an input that passes all rules (green border) |
.is-invalid | Added to an input that fails a rule (red border) |
.vd-validate-error | Auto-generated error message element shown below the invalid input |
Data Attributes
| Attribute | Description |
|---|---|
data-vd-validate | Place on a <form> to opt-in to validation |
data-vd-rules | Pipe-separated rule string on each input (e.g. "required|email|min:3") |
data-vd-validate-mode | When to validate: "blur" (default), "input", or "submit". Can be set per-form or per-field |
data-vd-msg-* | Custom error message per rule, e.g. data-vd-msg-required="Name is required" |
Composable API
| Symbol | Description |
|---|---|
useValidate(root) | Composable — wires every [data-vd-validate] form inside the root ref (blur/input/submit modes, error messages). Call once in setup(). |
(automatic cleanup) | Field listeners and error nodes are removed on component unmount. |
Events
| Event | Description |
|---|---|
validate:submit | Fired on the form on submit. event.detail is { valid } — a boolean indicating whether every field passed validation. |
Custom Rule Example
import { ref } from 'vue';
import { useValidate } from "@vanduo-oss/vd3";
const root = ref<HTMLElement | null>(null);
const { addRule } = useValidate(root);
addRule(
'noSpaces',
(value) => !/\s/.test(value),
'Value must not contain spaces'
);
// Usage: data-vd-rules="required|noSpaces"Accessibility
- Invalid fields receive
aria-invalid="true"; valid fields getaria-invalid="false" - Error messages are linked via
aria-describedbyso screen readers announce them - Error elements use
role="alert"for immediate announcement on live changes - Native
<form>semantics preserved —novalidatedisables browser UI, not semantics - Focus moves to the first invalid field on submit for keyboard users