Appearance
Form State API
Vorm provides full access to the internal form state through the useVorm() composable. It returns a powerful context object with reactive values and methods to interact with your form.
Basic Setup
ts
import { useVorm, type VormSchema } from 'vorm-vue';
const schema: VormSchema = [/* ... */];
const vorm = useVorm(schema, {
validationMode: 'onBlur' // 'onBlur' | 'onInput' | 'onSubmit'
});Reactive State
Form Data
ts
vorm.formData // Reactive form values
vorm.errors // Error messages per field (string | null)
vorm.touched // Whether field has been touched
vorm.dirty // Whether field value has changed
vorm.initial // Initial values at time of setFormData
vorm.validatedFields // Which fields have been validatedComputed State
ts
vorm.isValid // ComputedRef<boolean> - all validated fields pass
vorm.isDirty // ComputedRef<boolean> - any field is dirty
vorm.isTouched // ComputedRef<boolean> - any field is touchedComputedRef in Templates
These are ComputedRef values, not plain booleans. In templates you need .value:
vue
<!-- Option 1: Use .value -->
<button :disabled="!vorm.isValid.value">Submit</button>
<!-- Option 2: Destructure for auto-unwrapping -->
<script setup>
const { isValid } = vorm
</script>
<button :disabled="!isValid">Submit</button>This is standard Vue behavior for composables returning refs in objects (same as VueUse, TanStack Query, etc.).
Validation Methods
validate()
Validates all fields including repeater subfields. Returns true if all pass:
ts
async function handleSubmit() {
const isValid = await vorm.validate();
if (isValid) {
// Submit form
}
}validateFieldByName(name)
Validates a single field:
ts
await vorm.validateFieldByName('email');getValidationMode(name)
Returns the validation trigger for a field:
ts
vorm.getValidationMode('email'); // 'onBlur' | 'onInput' | 'onSubmit'Update Methods
updateField(name, value, options?)
Updates a single field with options:
ts
vorm.updateField('role', 'Admin', {
touched: true,
dirty: true,
validate: true,
fieldOptions: [
{ label: 'User', value: 'User' },
{ label: 'Admin', value: 'Admin' },
],
});updateFields(updates, options?)
Update multiple fields at once:
ts
vorm.updateFields(
{ role: 'Admin', username: 'flo' },
{
touched: true,
validate: true,
fieldOptions: {
role: [
{ label: 'User', value: 'User' },
{ label: 'Admin', value: 'Admin' },
],
},
}
);setFormData(data, options?)
Replace entire form data and reset state:
ts
vorm.setFormData(
{ username: 'flo', role: 'Moderator' },
{
fieldOptions: {
role: [
{ label: 'User', value: 'User' },
{ label: 'Moderator', value: 'Moderator' },
],
},
}
);resetForm()
Clears all values, errors, and state:
ts
vorm.resetForm();Error Methods
getErrors()
Returns a copy of current errors:
ts
const errors = vorm.getErrors();Clearing Errors
To clear errors, set them directly on the errors object:
ts
// Clear single error
vorm.errors.email = null;
// Clear all errors
Object.keys(vorm.errors).forEach(key => {
vorm.errors[key] = null;
});
// Or use resetForm() to reset everything
vorm.resetForm();Options Methods
getFieldOptions(name)
Returns resolved options for a select field:
ts
const options = vorm.getFieldOptions('country');
// Returns ComputedRef<Option[]>bindField(name)
Returns all bindings needed for custom components:
ts
const bindings = vorm.bindField('country');
// Returns ComputedRef<{
// modelValue: any;
// 'onUpdate:modelValue': (v) => void;
// items: Option[];
// options: Option[];
// error: string | undefined;
// errorMessages: string[];
// }>Usage with Vuetify:
vue
<v-select v-bind="vorm.bindField('country').value" />Repeater Methods
addRepeaterItem(path, item, index?)
Add item to repeater. The item parameter is required:
ts
// Add with initial data structure (recommended)
vorm.addRepeaterItem('contacts', { name: '', email: '' });
// Add empty object
vorm.addRepeaterItem('contacts', {});
// Insert at specific index
vorm.addRepeaterItem('contacts', { name: '' }, 0);Required Parameter
Unlike some form libraries, item is required. Always pass at least an empty object {}.
removeRepeaterItem(path, index)
Remove item by index:
ts
vorm.removeRepeaterItem('contacts', 2);moveRepeaterItem(path, from, to)
Reorder repeater items:
ts
vorm.moveRepeaterItem('contacts', 0, 2); // Move first to third positionclearRepeater(path)
Empty the repeater:
ts
vorm.clearRepeater('contacts');Utility Methods
touchAll()
Marks all fields as touched:
ts
vorm.touchAll();getTouched() / getDirty()
Returns copies of state maps:
ts
const touchedFields = vorm.getTouched();
const dirtyFields = vorm.getDirty();Complete Example
vue
<script setup lang="ts">
import { useVorm, type VormSchema, minLength } from 'vorm-vue';
import { VormProvider, AutoVorm } from 'vorm-vue';
const schema: VormSchema = [
{
name: 'email',
type: 'email',
label: 'Email',
validation: [{ rule: 'required' }, { rule: 'email' }],
},
{
name: 'password',
type: 'password',
label: 'Password',
validation: [{ rule: 'required' }, { rule: minLength(8) }],
},
];
const vorm = useVorm(schema, { validationMode: 'onBlur' });
async function handleSubmit() {
const isValid = await vorm.validate();
if (isValid) {
console.log('Submitting:', vorm.formData);
}
}
function handleReset() {
vorm.resetForm();
}
</script>
<template>
<VormProvider :vorm="vorm">
<AutoVorm as="form" @submit="handleSubmit">
<div class="buttons">
<button type="submit" :disabled="!vorm.isValid.value">Submit</button>
<button type="button" @click="handleReset">Reset</button>
</div>
</AutoVorm>
</VormProvider>
<!-- Debug info -->
<pre>{{ { isValid: vorm.isValid.value, isDirty: vorm.isDirty.value } }}</pre>
</template>The
useVorm()context is your gateway to dynamic form behavior, programmatic control, and granular state access.
