Skip to content

useForm — Formularios

useForm proporciona gestión de estado de formularios con validación, detección de errores visual y auto-sync de campos relacionados.


const {
formData, // shallowReactive con los valores actuales
invalidFields, // computed: true si hay al menos un campo inválido
markFieldAsTouched, // marca campo como "tocado" para mostrar errores
fillFormData, // rellena programáticamente (suprime watchers)
getFieldValidation // retorna { valid, showError } por campo
} = useForm({
name: '',
email: '',
phone: '',
country: '',
code: ''
})

Objeto shallowReactive con los valores. Se usa directamente con v-model:

<input v-model="formData.name" @blur="markFieldAsTouched('name')" />
<span v-if="getFieldValidation('name').showError">Campo requerido</span>

Los errores solo se muestran después de que el usuario interactúe con el campo:

markFieldAsTouched('email')
// Ahora getFieldValidation('email').showError puede ser true
const { valid, showError } = getFieldValidation('email')
// valid: si el campo pasa validación
// showError: solo true si es inválido Y fue tocado

// Deshabilitar botón de submit si hay errores
<button :disabled="invalidFields">Enviar</button>

Es true si cualquier campo del formulario no pasa validación.


Para rellenar el formulario programáticamente (ej: datos del usuario logueado):

fillFormData({
name: user.name,
email: user.email,
country: user.country
})

Importante: Suprime watchers durante el llenado para evitar side-effects no deseados.


Si el formulario tiene campos country y code, cambiar el país auto-actualiza el código telefónico:

// Usuario selecciona "México"
formData.country = 'MX'
// Automáticamente: formData.code = '+52'

Usa internamente la constante countriesPhone.ts para el mapeo.


<template>
<form @submit.prevent="handleSubmit">
<input
v-model="formData.name"
@blur="markFieldAsTouched('name')"
:class="{ 'border-red-500': getFieldValidation('name').showError }"
/>
<input
v-model="formData.email"
type="email"
@blur="markFieldAsTouched('email')"
/>
<button :disabled="invalidFields">Enviar</button>
</form>
</template>
<script setup lang="ts">
const { formData, invalidFields, markFieldAsTouched, getFieldValidation } = useForm({
name: '',
email: ''
})
function handleSubmit() {
// formData ya tiene los valores tipados
}
</script>