Vue JS Forms and Validation 2 — Questions and Answers
Question 1: How do you implement a basic validation that shows an error when a field is empty in Vue 3?
- Use a computed property or watcher to check the field's value and set an error message ref (Correct answer)
- Use the HTML required attribute only
- Use Vue's built-in v-validate directive
- Form validation requires a third-party library
Correct answer: Use a computed property or watcher to check the field's value and set an error message ref
Custom validation in Vue 3 is implemented with reactive state — a computed property or watcher that checks the value and sets an error message, displayed conditionally with `v-if`.
Simple custom validation: `const name = ref(''); const nameError = computed(() => !name.value.trim() ? 'Name is required' : ''); // template: <input v-model="name"> <p v-if="nameError">{{ nameError }}</p>`. For more control (show error only after touch/blur): `const touched = ref(false); const showError = computed(() => touched.value && !name.value.trim())`. VeeValidate and Vuelidate automate this pattern with additional features like async validation, cross-field validation, and built-in rules.
Question 2: How do you use VeeValidate's `useField` composable in Vue 3?
- const { value, errorMessage } = useField('fieldName', validationRule) (Correct answer)
- const field = new VeeValidate.Field('name', rule)
- useField is not available in Composition API
- const { v$ } = useVuelidate({ name: required }, { name })
Correct answer: const { value, errorMessage } = useField('fieldName', validationRule)
`useField` from VeeValidate v4 provides a field value ref and an error message ref tied to validation rules. It integrates with a parent `useForm` context.
`const { value, errorMessage } = useField('email', email => isValidEmail(email) || 'Invalid email')`. The `value` is a reactive ref you bind to the input: `:value="value" @input="value = $event.target.value"` (or `v-model="value"`). `errorMessage` is a computed ref that holds the validation message when invalid. VeeValidate automatically validates on input, blur, or submission. `useField` must be called inside a `useForm` context or as a standalone field. Schema-based validation with Yup: `useField('email', yup.string().email())`.
Question 3: What is the purpose of `v-model.lazy` in Vue 3?
- Syncs the input value on the `change` event instead of `input`, reducing update frequency (Correct answer)
- Delays the v-model binding until the component is fully mounted
- Applies lazy loading to the form element
- Only validates on form submission
Correct answer: Syncs the input value on the `change` event instead of `input`, reducing update frequency
`.lazy` changes `v-model` to sync on the `change` event (typically on blur or Enter) rather than on every `input` event, reducing reactivity triggers while the user types.
By default, `v-model` on text inputs syncs on every `input` event (every keystroke). With `.lazy`, it syncs on the `change` event, which fires when the input loses focus or Enter is pressed. This is useful when: validation or transformation is expensive, you're making API calls on input changes, or you want to avoid unnecessary re-renders while the user is still typing. `v-model.lazy` + `v-model.trim` can be combined: `v-model.lazy.trim` syncs on change and trims whitespace.
Question 4: How do you reset a form in Vue 3 without a form validation library?
- Reset each ref to its initial value manually, or use a reactive object and reassign it (Correct answer)
- Call form.value.reset()
- Use document.getElementById('form').reset()
- Call Vue.resetForm(data)
Correct answer: Reset each ref to its initial value manually, or use a reactive object and reassign it
Without a library, form reset means reassigning all reactive refs to empty/initial values. For objects, you can reassign `Object.assign(formData, initialValues)` or spread initial values.
With individual refs: `name.value = ''; email.value = ''; agreed.value = false`. With a reactive object: `const form = reactive({ name: '', email: '' }); function resetForm() { Object.assign(form, { name: '', email: '' }) }`. With a ref containing an object: `form.value = { name: '', email: '' }`. If using a validation library, call its reset function (VeeValidate: `resetForm()`, Vuelidate: `v$.value.$reset()`). Native `HTMLFormElement.reset()` works for DOM-driven forms but won't update Vue's reactive state.
Question 5: In Vue 3, how do you implement a select dropdown bound to an object value with `v-model`?
- Bind v-model to a ref and use :value on options to bind to object references (Correct answer)
- Select elements can only bind to strings with v-model
- Use value.id in v-model and reconstruct the object in a watcher
- Select requires a special component for object values
Correct answer: Bind v-model to a ref and use :value on options to bind to object references
Vue 3's `v-model` on select supports non-string values. Using `:value="option"` (not `value="..."`) binds the whole object, and Vue uses reference equality to determine the selected option.
`<select v-model="selectedUser"><option v-for="user in users" :key="user.id" :value="user">{{ user.name }}</option></select>`. When an option is selected, `selectedUser` is set to the corresponding `user` object from the array. Vue uses `===` comparison between `v-model`'s value and each option's `:value` to determine which option is shown as selected. This means the selected object must be the same reference as in the options array. If objects come from different sources, compare by ID: consider computing the selected user from an `selectedUserId` ref.
Question 6: How do you dynamically add and remove form fields (array of inputs) in Vue 3?
- Store inputs in a reactive array and use v-for; add/remove items from the array (Correct answer)
- Use a v-dynamic directive on the form
- Register each dynamic input as a separate component
- Dynamic fields require FormKit or VeeValidate
Correct answer: Store inputs in a reactive array and use v-for; add/remove items from the array
Dynamic form fields are managed by keeping an array of data objects in reactive state and rendering inputs with `v-for`. Adding/removing array items adds/removes fields from the DOM.
`const fields = ref([{ value: '' }]); function addField() { fields.value.push({ value: '' }) }; function removeField(index) { fields.value.splice(index, 1) }`. Template: `<div v-for="(field, i) in fields" :key="i"><input v-model="field.value"><button @click="removeField(i)">Remove</button></div>`. Always provide a stable `:key` — using the index works for append-only lists but use a unique ID (e.g., incrementing counter) if fields can be reordered or removed from the middle. Collect values on submit by mapping `fields.value.map(f => f.value)`.
How do you implement a basic validation that shows an error when a field is empty in Vue 3?