v-model personalizado en componentes Vue

Resumen

Crear componentes personalizados con v-model en Vue.js te permite sincronizar datos entre un componente padre y uno hijo con una sintaxis mucho más limpia que usar v-bind y v-on por separado. Si ya dominas props y eventos personalizados, este es el siguiente paso para construir componentes reutilizables y reactivos.

¿Cómo se comunica un componente padre con un componente hijo en Vue?

La comunicación entre componentes en Vue.js sigue una regla clara: los datos bajan por props y suben por eventos. Para verlo en acción, partimos de un proyecto nuevo con un componente raíz y un componente hijo llamado v-input, que envuelve un <input type="text"> nativo de HTML.

En el padre defines una variable dentro de la función data, por ejemplo text con el valor "Hola, Vue". Para enviarla al hijo usas v-bind sobre un prop llamado value, y dentro del componente hijo lo declaras en el atributo props (en plural, no prop, un detalle que rompe la reactividad si lo escribes mal).

¿Qué es un prop en Vue.js? Es una propiedad que el componente padre pasa al hijo para inyectarle datos. Se declara en el array props del hijo y se enlaza con v-bind desde el padre.

Una vez que el dato llega al hijo, lo conectas al atributo value del input usando v-bind:value="value". Así el input ya muestra el texto del padre.

¿Cómo emitir cambios desde el componente hijo hacia el padre?

Recibir datos no basta: necesitas que los cambios dentro del input se propaguen de vuelta. Aquí entra el evento input de Vue, que detecta cada modificación del campo.

En el hijo escuchas el evento con v-on:input y ejecutas un método que recibe el evento nativo. Desde ese evento accedes al texto escrito mediante event.target.value. Después, en lugar de imprimirlo en consola, lo emites al padre con this.$emit.

El flujo queda así:

  • El input dispara el evento input en cada tecleo.
  • El método del hijo captura event.target.value.
  • Se emite un evento personalizado, por ejemplo update, con la cadena de texto.
  • El padre escucha ese evento y actualiza la variable text en su propio método.

Un detalle importante: si nombras tu evento personalizado igual que un evento nativo como input, Vue puede confundirse y disparar comportamientos inesperados. Renombrarlo a algo como updates resuelve ese conflicto.

¿Por qué usar $emit en lugar de modificar el prop directamente? Porque en Vue los props son unidireccionales: el hijo no puede mutar lo que recibe del padre. Emitir un evento es la forma correcta de pedirle al padre que actualice su variable.

¿Cómo crear un v-model personalizado en un componente Vue?

Cuando ya tienes un v-bind para recibir el valor y un v-on para emitir cambios, Vue te ofrece una sintaxis más corta: tu propio v-model personalizado.

En lugar de escribir en el padre algo como v-bind:value="text" junto a v-on:updates="miHandler", basta con escribir v-model:value="text". Vue se encarga del resto, siempre que sigas dos reglas dentro del componente hijo:

  1. Recibir el dato como un prop con el nombre que vas a sincronizar, por ejemplo value.
  2. Emitir el evento con el nombre exacto update:value, donde value es el mismo nombre del prop.

Ese prefijo update: es obligatorio. Antes podías llamar al evento como quisieras, pero al usar v-model Vue exige esa convención para enlazar automáticamente la variable reactiva.

¿Qué nombre puedo darle al prop usado con v-model? Cualquiera. Si lo llamas texto en vez de value, solo debes usar v-model:texto en el padre y emitir update:texto desde el hijo.

¿Qué tipos de datos admite un v-model personalizado?

No estás limitado a cadenas de texto. Tu componente con v-model puede sincronizar:

  • Variables tipo string, como en el ejemplo del input.
  • Valores booleanos, útiles para toggles o checkboxes personalizados.
  • Variables numéricas para sliders o contadores.
  • Objetos JSON completos cuando manejas formularios complejos.
  • Listas o arrays para selectores múltiples.

Esto convierte a v-model en una herramienta flexible para construir componentes que se comporten igual de bien que los inputs nativos de HTML, pero con la lógica que tú definas.

¿Cuándo conviene usar v-model en lugar de v-bind y v-on?

La regla práctica es simple: si tu componente recibe un valor, lo modifica internamente y necesita devolver ese cambio al padre, v-model te ahorra código y hace el componente más legible para quien lo consume. Si solo necesitas pasar datos en una dirección, basta con v-bind. Si solo necesitas escuchar acciones puntuales sin sincronizar estado, v-on es suficiente.

Anímate a construir tu propio componente con v-model, ya sea un input estilizado, un selector de color o un toggle, y compártelo en los comentarios para recibir retroalimentación.