0
# State Access
1
2
Composables for accessing reactive form and field state information. These composables provide read-only access to various aspects of form and field state for reactive UI updates and conditional logic.
3
4
## Capabilities
5
6
### Field State Access
7
8
#### useFieldValue Composable
9
10
Gets reactive access to a field's current value.
11
12
```typescript { .api }
13
/**
14
* Gets reactive access to a field's current value
15
* @param path - Field path (uses injected field context if omitted)
16
* @returns Computed ref to field value
17
*/
18
function useFieldValue<TValue = unknown>(path?: MaybeRefOrGetter<string>): ComputedRef<TValue | undefined>;
19
```
20
21
#### useFieldError Composable
22
23
Gets reactive access to a field's error message.
24
25
```typescript { .api }
26
/**
27
* Gets reactive access to a field's error message
28
* @param path - Field path (uses injected field context if omitted)
29
* @returns Computed ref to field error message
30
*/
31
function useFieldError(path?: MaybeRefOrGetter<string>): ComputedRef<string | undefined>;
32
```
33
34
**Field State Examples:**
35
36
```typescript
37
import { useFieldValue, useFieldError, useField } from "vee-validate";
38
39
// Using with explicit path
40
const email = useFieldValue('email');
41
const emailError = useFieldError('email');
42
43
// Using within field context (path omitted)
44
const EmailField = {
45
setup() {
46
const field = useField('email', 'required|email');
47
48
// These will automatically use the 'email' field context
49
const value = useFieldValue(); // Same as field.value
50
const error = useFieldError(); // Same as field.errorMessage
51
52
return { value, error };
53
}
54
};
55
56
// Reactive field path
57
const currentField = ref('username');
58
const fieldValue = useFieldValue(currentField);
59
const fieldError = useFieldError(currentField);
60
61
// Watch field changes
62
watchEffect(() => {
63
console.log(`${currentField.value} value:`, fieldValue.value);
64
if (fieldError.value) {
65
console.log(`${currentField.value} error:`, fieldError.value);
66
}
67
});
68
69
// Computed properties based on field state
70
const isEmailValid = computed(() => {
71
const emailVal = useFieldValue('email');
72
const emailErr = useFieldError('email');
73
return emailVal.value && !emailErr.value;
74
});
75
```
76
77
### Form State Access
78
79
#### useFormValues Composable
80
81
Gets reactive access to all form values.
82
83
```typescript { .api }
84
/**
85
* Gets reactive access to all form values
86
* @returns Computed ref to form values object
87
*/
88
function useFormValues<TValues extends GenericObject = GenericObject>(): ComputedRef<Partial<TValues>>;
89
```
90
91
#### useFormErrors Composable
92
93
Gets reactive access to all form errors.
94
95
```typescript { .api }
96
/**
97
* Gets reactive access to all form errors
98
* @returns Computed ref to form errors object
99
*/
100
function useFormErrors<TValues extends GenericObject = GenericObject>(): ComputedRef<FormErrors<TValues>>;
101
102
type FormErrors<TValues extends GenericObject> = Partial<Record<Path<TValues> | '', string | undefined>>;
103
```
104
105
**Form State Examples:**
106
107
```typescript
108
import { useFormValues, useFormErrors, useForm } from "vee-validate";
109
110
// Setup form context
111
const { handleSubmit } = useForm();
112
113
// Access form state
114
const formValues = useFormValues();
115
const formErrors = useFormErrors();
116
117
// Watch form changes
118
watchEffect(() => {
119
console.log('Current form values:', formValues.value);
120
console.log('Current form errors:', formErrors.value);
121
});
122
123
// Computed properties based on form state
124
const hasErrors = computed(() => {
125
return Object.keys(formErrors.value).length > 0;
126
});
127
128
const formDataSummary = computed(() => {
129
const values = formValues.value;
130
return {
131
fieldCount: Object.keys(values).length,
132
filledFields: Object.values(values).filter(v => v !== '' && v != null).length,
133
hasData: Object.values(values).some(v => v !== '' && v != null)
134
};
135
});
136
137
// Form validation summary
138
const validationSummary = computed(() => {
139
const errors = formErrors.value;
140
const errorFields = Object.keys(errors).filter(key => errors[key]);
141
142
return {
143
isValid: errorFields.length === 0,
144
errorCount: errorFields.length,
145
errorFields,
146
firstError: errorFields.length > 0 ? errors[errorFields[0]] : null
147
};
148
});
149
```
150
151
### Validation State Access
152
153
#### useIsFieldDirty Composable
154
155
Checks if field value differs from initial value.
156
157
```typescript { .api }
158
/**
159
* Checks if field value differs from initial value
160
* @param path - Field path (uses injected field context if omitted)
161
* @returns Computed ref to field dirty state
162
*/
163
function useIsFieldDirty(path?: MaybeRefOrGetter<string>): ComputedRef<boolean>;
164
```
165
166
#### useIsFieldTouched Composable
167
168
Checks if field has been interacted with.
169
170
```typescript { .api }
171
/**
172
* Checks if field has been interacted with
173
* @param path - Field path (uses injected field context if omitted)
174
* @returns Computed ref to field touched state
175
*/
176
function useIsFieldTouched(path?: MaybeRefOrGetter<string>): ComputedRef<boolean>;
177
```
178
179
#### useIsFieldValid Composable
180
181
Checks if field passes validation.
182
183
```typescript { .api }
184
/**
185
* Checks if field passes validation
186
* @param path - Field path (uses injected field context if omitted)
187
* @returns Computed ref to field valid state
188
*/
189
function useIsFieldValid(path?: MaybeRefOrGetter<string>): ComputedRef<boolean>;
190
```
191
192
**Field Validation State Examples:**
193
194
```typescript
195
import {
196
useIsFieldDirty,
197
useIsFieldTouched,
198
useIsFieldValid,
199
useField
200
} from "vee-validate";
201
202
// Field state composables with explicit paths
203
const isEmailDirty = useIsFieldDirty('email');
204
const isEmailTouched = useIsFieldTouched('email');
205
const isEmailValid = useIsFieldValid('email');
206
207
// Combined field state checks
208
const emailFieldStatus = computed(() => {
209
if (!isEmailTouched.value) return 'untouched';
210
if (!isEmailValid.value) return 'invalid';
211
if (isEmailDirty.value) return 'modified';
212
return 'valid';
213
});
214
215
// Using within field context
216
const EmailField = {
217
setup() {
218
useField('email', 'required|email');
219
220
const isDirty = useIsFieldDirty();
221
const isTouched = useIsFieldTouched();
222
const isValid = useIsFieldValid();
223
224
const showValidationIcon = computed(() => {
225
return isTouched.value && (isValid.value || !isValid.value);
226
});
227
228
const fieldClasses = computed(() => ({
229
'field-untouched': !isTouched.value,
230
'field-dirty': isDirty.value,
231
'field-valid': isTouched.value && isValid.value,
232
'field-invalid': isTouched.value && !isValid.value
233
}));
234
235
return {
236
isDirty,
237
isTouched,
238
isValid,
239
showValidationIcon,
240
fieldClasses
241
};
242
}
243
};
244
245
// Reactive field paths
246
const activeField = ref('username');
247
const isActiveFieldDirty = useIsFieldDirty(activeField);
248
const isActiveFieldValid = useIsFieldValid(activeField);
249
250
// Watch state changes
251
watch([isActiveFieldDirty, isActiveFieldValid], ([dirty, valid]) => {
252
console.log(`${activeField.value} state:`, { dirty, valid });
253
});
254
```
255
256
### Form Validation State Access
257
258
#### useIsFormDirty Composable
259
260
Checks if any form field is dirty.
261
262
```typescript { .api }
263
/**
264
* Checks if any form field is dirty
265
* @returns Computed ref to form dirty state
266
*/
267
function useIsFormDirty(): ComputedRef<boolean>;
268
```
269
270
#### useIsFormTouched Composable
271
272
Checks if any form field is touched.
273
274
```typescript { .api }
275
/**
276
* Checks if any form field is touched
277
* @returns Computed ref to form touched state
278
*/
279
function useIsFormTouched(): ComputedRef<boolean>;
280
```
281
282
#### useIsFormValid Composable
283
284
Checks if entire form is valid.
285
286
```typescript { .api }
287
/**
288
* Checks if entire form is valid
289
* @returns Computed ref to form valid state
290
*/
291
function useIsFormValid(): ComputedRef<boolean>;
292
```
293
294
#### useIsSubmitting Composable
295
296
Checks if form is currently submitting.
297
298
```typescript { .api }
299
/**
300
* Checks if form is currently submitting
301
* @returns Computed ref to form submitting state
302
*/
303
function useIsSubmitting(): ComputedRef<boolean>;
304
```
305
306
#### useIsValidating Composable
307
308
Checks if form is currently validating.
309
310
```typescript { .api }
311
/**
312
* Checks if form is currently validating
313
* @returns Computed ref to form validating state
314
*/
315
function useIsValidating(): ComputedRef<boolean>;
316
```
317
318
**Form Validation State Examples:**
319
320
```typescript
321
import {
322
useIsFormDirty,
323
useIsFormTouched,
324
useIsFormValid,
325
useIsSubmitting,
326
useIsValidating,
327
useForm
328
} from "vee-validate";
329
330
// Setup form
331
const { handleSubmit } = useForm();
332
333
// Form state composables
334
const isFormDirty = useIsFormDirty();
335
const isFormTouched = useIsFormTouched();
336
const isFormValid = useIsFormValid();
337
const isSubmitting = useIsSubmitting();
338
const isValidating = useIsValidating();
339
340
// Combined form state
341
const formState = computed(() => ({
342
dirty: isFormDirty.value,
343
touched: isFormTouched.value,
344
valid: isFormValid.value,
345
submitting: isSubmitting.value,
346
validating: isValidating.value
347
}));
348
349
// Form status computed properties
350
const canSubmit = computed(() => {
351
return isFormValid.value && !isSubmitting.value && !isValidating.value;
352
});
353
354
const showUnsavedWarning = computed(() => {
355
return isFormDirty.value && !isSubmitting.value;
356
});
357
358
const formStatus = computed(() => {
359
if (isSubmitting.value) return 'submitting';
360
if (isValidating.value) return 'validating';
361
if (!isFormTouched.value) return 'pristine';
362
if (!isFormValid.value) return 'invalid';
363
if (isFormDirty.value) return 'modified';
364
return 'valid';
365
});
366
367
// Button states based on form state
368
const submitButtonProps = computed(() => ({
369
disabled: !canSubmit.value,
370
loading: isSubmitting.value,
371
text: isSubmitting.value ? 'Submitting...' : 'Submit'
372
}));
373
374
const resetButtonProps = computed(() => ({
375
disabled: !isFormDirty.value || isSubmitting.value,
376
visible: isFormDirty.value
377
}));
378
379
// Form progress indicator
380
const formProgress = computed(() => {
381
const touched = isFormTouched.value;
382
const valid = isFormValid.value;
383
const dirty = isFormDirty.value;
384
385
if (!touched) return { step: 0, label: 'Start filling the form' };
386
if (!valid) return { step: 1, label: 'Fix validation errors' };
387
if (dirty) return { step: 2, label: 'Ready to submit' };
388
return { step: 3, label: 'Form completed' };
389
});
390
391
// Watch form state changes
392
watchEffect(() => {
393
if (showUnsavedWarning.value) {
394
// Show browser warning about unsaved changes
395
window.addEventListener('beforeunload', handleBeforeUnload);
396
} else {
397
window.removeEventListener('beforeunload', handleBeforeUnload);
398
}
399
});
400
401
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
402
e.preventDefault();
403
e.returnValue = 'You have unsaved changes. Are you sure you want to leave?';
404
return e.returnValue;
405
};
406
```
407
408
### Advanced State Access Patterns
409
410
#### Custom State Selectors
411
412
Creating custom computed properties based on multiple state sources.
413
414
```typescript
415
import {
416
useFormValues,
417
useFormErrors,
418
useIsFormValid,
419
useIsFormDirty
420
} from "vee-validate";
421
422
// Custom selectors
423
const formValues = useFormValues();
424
const formErrors = useFormErrors();
425
const isFormValid = useIsFormValid();
426
const isFormDirty = useIsFormDirty();
427
428
// Complex state selectors
429
const formCompleteness = computed(() => {
430
const values = formValues.value;
431
const requiredFields = ['name', 'email', 'phone'];
432
const filledRequired = requiredFields.filter(field => values[field]).length;
433
434
return {
435
percentage: (filledRequired / requiredFields.length) * 100,
436
filledFields: filledRequired,
437
totalRequired: requiredFields.length,
438
isComplete: filledRequired === requiredFields.length
439
};
440
});
441
442
const validationSummary = computed(() => {
443
const errors = formErrors.value;
444
const errorEntries = Object.entries(errors).filter(([_, error]) => error);
445
446
return {
447
hasErrors: errorEntries.length > 0,
448
errorCount: errorEntries.length,
449
fields: errorEntries.map(([field, error]) => ({ field, error })),
450
severity: errorEntries.length > 3 ? 'high' : errorEntries.length > 0 ? 'medium' : 'none'
451
};
452
});
453
454
const formHealthScore = computed(() => {
455
const valid = isFormValid.value;
456
const dirty = isFormDirty.value;
457
const completeness = formCompleteness.value.percentage;
458
const errors = validationSummary.value.errorCount;
459
460
let score = 0;
461
if (valid) score += 40;
462
if (completeness > 80) score += 30;
463
if (dirty && valid) score += 20;
464
if (errors === 0) score += 10;
465
466
return {
467
score,
468
grade: score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'D',
469
status: score >= 90 ? 'excellent' : score >= 80 ? 'good' : score >= 70 ? 'fair' : 'poor'
470
};
471
});
472
```