Vue Built-in Attributes
Special attributes for enhanced functionality
🏷️ Built-in Attributes
Vue provides special built-in attributes like key, ref, and is for enhanced component functionality. These attributes help with list rendering optimization, DOM access, dynamic components, and performance improvements in your applications.
<!-- Using built-in attributes -->
<template>
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</template>
Core Built-in Attributes
key
Unique identifier for list items
<div
v-for="item in items"
:key="item.id"
>
ref
Direct DOM element access
<input ref="inputRef" />
// Access: inputRef.value
is
Dynamic component rendering
<component
:is="currentComponent"
/>
v-once
Render element only once
<div v-once>
{{ staticContent }}
</div>
🔹 The key Attribute
Use key for efficient list rendering:
<script setup>
const users = ref([
{ id: 1, name: 'John', age: 25 },
{ id: 2, name: 'Jane', age: 30 },
{ id: 3, name: 'Bob', age: 35 }
])
function removeUser(id) {
users.value = users.value.filter(u => u.id !== id)
}
</script>
<template>
<div>
<!-- ✅ GOOD: Using unique key -->
<div
v-for="user in users"
:key="user.id"
class="user-card"
>
<h3>{{ user.name }}</h3>
<p>Age: {{ user.age }}</p>
<button @click="removeUser(user.id)">Remove</button>
</div>
<!-- ❌ BAD: Using index as key -->
<div
v-for="(user, index) in users"
:key="index"
>
{{ user.name }}
</div>
</div>
</template>
Why use key?
- Helps Vue track element identity
- Improves rendering performance
- Prevents state bugs in lists
- Always use unique, stable values
🔹 The ref Attribute
Access DOM elements and components directly:
<script setup>
import { ref, onMounted } from 'vue'
// Template refs
const inputRef = ref(null)
const componentRef = ref(null)
onMounted(() => {
// Focus input on mount
inputRef.value.focus()
// Access component methods
componentRef.value.someMethod()
})
function handleClick() {
// Get input value
console.log(inputRef.value.value)
// Manipulate DOM
inputRef.value.style.border = '2px solid blue'
}
</script>
<template>
<div>
<!-- Element ref -->
<input
ref="inputRef"
type="text"
placeholder="Type here..."
/>
<button @click="handleClick">Get Value</button>
<!-- Component ref -->
<ChildComponent ref="componentRef" />
</div>
</template>
🔹 The is Attribute
Dynamically switch between components:
<script setup>
import { ref } from 'vue'
import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'
import ContactView from './ContactView.vue'
const currentView = ref('HomeView')
const components = {
HomeView,
AboutView,
ContactView
}
</script>
<template>
<div>
<!-- Navigation -->
<button @click="currentView = 'HomeView'">Home</button>
<button @click="currentView = 'AboutView'">About</button>
<button @click="currentView = 'ContactView'">Contact</button>
<!-- Dynamic component -->
<component :is="components[currentView]" />
<!-- With KeepAlive to preserve state -->
<KeepAlive>
<component :is="components[currentView]" />
</KeepAlive>
</div>
</template>
🔹 v-once Directive
Render content only once for performance:
<script setup>
const staticTitle = ref('Welcome to Vue')
const dynamicCount = ref(0)
</script>
<template>
<div>
<!-- Rendered once, never updates -->
<h1 v-once>{{ staticTitle }}</h1>
<!-- Updates on every change -->
<p>Count: {{ dynamicCount }}</p>
<button @click="dynamicCount++">Increment</button>
<!-- Static content with v-once -->
<div v-once>
<p>This content is rendered once</p>
<p>Even if data changes, this won't update</p>
</div>
</div>
</template>
Use v-once for: Static content, terms and conditions, copyright notices, or any content that never changes
🔹 v-memo Directive
Memoize template sub-trees for performance:
<script setup>
const items = ref([
{ id: 1, name: 'Item 1', selected: false },
{ id: 2, name: 'Item 2', selected: false },
{ id: 3, name: 'Item 3', selected: false }
])
const globalCount = ref(0)
</script>
<template>
<div>
<p>Global Count: {{ globalCount }}</p>
<button @click="globalCount++">Increment</button>
<!-- Only re-renders when item.selected changes -->
<div
v-for="item in items"
:key="item.id"
v-memo="[item.selected]"
>
<h3>{{ item.name }}</h3>
<p>Selected: {{ item.selected }}</p>
<button @click="item.selected = !item.selected">
Toggle
</button>
</div>
</div>
</template>
🔹 v-cloak Directive
Hide uncompiled templates until ready:
<template>
<!-- Prevents flash of uncompiled content -->
<div v-cloak>
<h1>{{ title }}</h1>
<p>{{ description }}</p>
</div>
</template>
<style>
/* Hide element until Vue is ready */
[v-cloak] {
display: none;
}
</style>
🔹 v-pre Directive
Skip compilation for raw content:
<template>
<div>
<!-- Vue will compile this -->
<p>{{ message }}</p>
<!-- Vue will skip this, show raw mustaches -->
<p v-pre>{{ This will not be compiled }}</p>
<!-- Useful for displaying Vue syntax -->
<pre v-pre>
<code>
<template>
{{ message }}
</template>
</code>
</pre>
</div>
</template>