Fix: useTemplateRef Already Exists in Vue.js

Error message:
useTemplateRef('
Composition API 2025-01-25

What Causes This Warning?

This warning occurs when you call useTemplateRef() multiple times with the same key. Each template ref key should be unique and defined only once.

The Problem

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

// ❌ Duplicate template ref keys
const inputRef = useTemplateRef('input')
const anotherInputRef = useTemplateRef('input') // Warning!
</script>

The Fix

Use Unique Keys

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

// ✅ Unique keys for each ref
const usernameRef = useTemplateRef('username')
const emailRef = useTemplateRef('email')
const passwordRef = useTemplateRef('password')
</script>

<template>
  <input ref="username" />
  <input ref="email" />
  <input ref="password" />
</template>

Single Declaration Per Key

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

// ✅ Declare once, use anywhere
const inputRef = useTemplateRef('input')

onMounted(() => {
  inputRef.value?.focus()
})

function clearInput() {
  if (inputRef.value) {
    inputRef.value.value = ''
  }
}
</script>

<template>
  <input ref="input" />
  <button @click="clearInput">Clear</button>
</template>

Common Scenarios

Accidental Duplication

<!-- ❌ Might happen with copy-paste -->
<script setup>
const ref1 = useTemplateRef('element')
// ... lots of code ...
const ref2 = useTemplateRef('element') // Forgot this exists!
</script>

<!-- ✅ Check for existing refs before adding -->
<script setup>
const elementRef = useTemplateRef('element')
// Use elementRef throughout
</script>

In Composables

// ❌ Composable called multiple times
export function useInput(key) {
  const ref = useTemplateRef(key) // Duplicate if same key!
  return ref
}

// Usage
const input1 = useInput('input') // OK
const input2 = useInput('input') // Warning!

// ✅ Pass ref from outside or use unique keys
export function useInput(inputRef) {
  // Work with provided ref
  return {
    focus: () => inputRef.value?.focus(),
    clear: () => {
      if (inputRef.value) inputRef.value.value = ''
    }
  }
}

// Usage
const inputRef = useTemplateRef('input')
const { focus, clear } = useInput(inputRef)

Dynamic Refs

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

// ❌ Can't use useTemplateRef dynamically in loop
// items.forEach(item => useTemplateRef(item.id)) // Bad!

// ✅ Use ref array for lists
const itemRefs = ref([])

function setItemRef(el, index) {
  itemRefs.value[index] = el
}
</script>

<template>
  <div
    v-for="(item, index) in items"
    :key="item.id"
    :ref="el => setItemRef(el, index)"
  >
    {{ item.name }}
  </div>
</template>

Traditional ref() Alternative

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

// ✅ Traditional approach still works
const inputRef = ref(null)
</script>

<template>
  <input ref="inputRef" />
</template>

useTemplateRef vs ref()

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

// Both approaches work:

// Approach 1: Traditional ref
const traditionalRef = ref(null)

// Approach 2: useTemplateRef (Vue 3.5+)
const templateRef = useTemplateRef('myElement')
</script>

<template>
  <!-- Traditional: ref name matches variable name -->
  <div ref="traditionalRef">Traditional</div>

  <!-- useTemplateRef: ref name matches key parameter -->
  <div ref="myElement">Template Ref</div>
</template>

Quick Checklist

  • Use unique keys for each useTemplateRef() call
  • Don’t duplicate useTemplateRef() with same key
  • For lists, use callback refs with ref() array
  • Traditional ref() approach still works
  • Check existing refs before adding new ones