Skip to content
← Todas las preguntas
⚡ Intermedio

¿Cómo funcionan los template refs?

🧩 Componentes🔗 Composition API

Los template refs te dan acceso directo a un elemento DOM o a la instancia de un componente hijo. Añades un atributo ref en el template y lees el valor correspondiente en el script después de que el componente se monte. Consulta la guía de Template Refs para más detalles.

Patrón anterior (antes de Vue 3.5)

El nombre de la variable en el script debe coincidir exactamente con el atributo ref. Si no coinciden, el ref es silenciosamente null sin ningún aviso.

vue
<script setup>
import { ref, onMounted } from 'vue'

const inputEl = (ref < HTMLInputElement) | (null > null)

onMounted(() => {
  inputEl.value?.focus()
})
</script>

<template>
  <!-- el nombre DEBE ser "inputEl" para coincidir con la variable -->
  <input ref="inputEl" />
</template>
Open in Vue Playground

El punto frágil: renombra la variable durante una refactorización y la conexión se rompe silenciosamente.

useTemplateRef (Vue 3.5+)

useTemplateRef desacopla el nombre de la variable del atributo ref. El argumento de texto es el punto de conexión, y la variable puede llamarse de cualquier manera.

vue
<script setup>
import { useTemplateRef, onMounted } from 'vue'

const searchInput = useTemplateRef('search-box')

onMounted(() => {
  searchInput.value?.focus()
})
</script>

<template>
  <input ref="search-box" type="search" />
</template>
Open in Vue Playground

Ventajas: autocompletado en el IDE para nombres de ref, mejor inferencia de TypeScript, y los errores tipográficos producen errores visibles en lugar de nulls silenciosos.

Refs con v-for

Cuando se usan dentro de v-for, el ref se puebla automaticamente con un array de elementos.

Advertencia: El array de refs no garantiza el mismo orden que el array de origen. Si necesitas hacer coincidir elementos con items del array por indice, usa una estrategia diferente como un Map con clave por ID del item o un function ref.

useTemplateRef (Vue 3.5+, recomendado)

vue
<script setup>
import { useTemplateRef, onMounted } from 'vue'

const itemRefs = useTemplateRef<HTMLLIElement[]>('items')

onMounted(() => {
  itemRefs.value?.forEach(el => {
    console.log(el.textContent)
  })
})
</script>

<template>
  <ul>
    <li v-for="item in items" ref="items" :key="item.id">
      {{ item.text }}
    </li>
  </ul>
</template>
Open in Vue Playground

Patrón con ref() (antes de Vue 3.5)

vue
<script setup>
import { ref, onMounted } from 'vue'

const itemRefs = ref<HTMLLIElement[]>([])

onMounted(() => {
  itemRefs.value.forEach(el => {
    console.log(el.textContent)
  })
})
</script>

<template>
  <ul>
    <li v-for="item in items" ref="itemRefs" :key="item.id">
      {{ item.text }}
    </li>
  </ul>
</template>
Open in Vue Playground

Refs en componentes

Un template ref en un componente hijo te da la instancia pública del componente, no un elemento DOM. Con <script setup>, el hijo no expone nada por defecto. Necesitas defineExpose para hacer accesibles las propiedades.

vue
<!-- ChildForm.vue -->
<script setup>
import { ref } from 'vue'

const formData = ref({ name: '' })

function validate() {
  return formData.value.name.length > 0
}

defineExpose({ validate })
</script>
Open in Vue Playground
vue
<!-- Parent.vue -->
<script setup>
import { useTemplateRef } from 'vue'

const formRef = useTemplateRef('child-form')

function submit() {
  if (formRef.value?.validate()) {
    // continuar
  }
}
</script>

<template>
  <ChildForm ref="child-form" />
  <button @click="submit">Enviar</button>
</template>
Open in Vue Playground

Cuándo usar template refs

Situación¿Usar un ref?
Enfocar un input, hacer scroll a un elemento
Integrar una librería no Vue (gráfico, mapa)
Leer dimensiones de un elemento
Cambiar texto o alternar clasesNo, usa datos reactivos y bindings
Escuchar eventosNo, usa @evento

Ver también: ¿Qué es defineExpose y cuándo es necesario? · ¿Se puede usar await directamente en script setup?

Referencias

Publicado bajo la licencia MIT.