Vue Templates
Vue templates describe the DOM you want using HTML enriched with mustache interpolation and directives, and Vue compiles that description into an efficient render function for you.
What a Template Actually Is
A Vue template is valid, mostly-ordinary HTML with a small extra syntax layered on top: double-curly interpolation for text, and special attributes called directives for everything else. You never write render-function code by hand -- Vue's compiler does that at build time, turning your markup into a fast function that produces virtual DOM nodes. That compilation step is also why templates can catch mistakes, like referencing an undeclared variable, before your app ever runs in a browser.
Text Interpolation with Mustaches
Double curly braces, often called mustaches, let you drop the result of a JavaScript expression into text content. Anything between the braces is evaluated as a single expression -- not a full statement -- so a ternary or a method call works, but an if statement or a variable declaration does not. The result is automatically converted to a string and, critically, escaped, so interpolated text can never inject live HTML tags into the page.
Interpolating Values and Expressions
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Ada')
const tasksLeft = ref(3)
const summary = computed(() =>
tasksLeft.value === 0 ? 'All done!' : `${tasksLeft.value} tasks left`
)
</script>
<template>
<h2>Hello, {{ firstName }}</h2>
<p>{{ summary }}</p>
<p>Shouting version: {{ firstName.toUpperCase() }}</p>
</template>Binding Attributes with v-bind
Mustaches only work inside text content, not inside HTML attributes -- you can't write id='{{ someId }}'. For attributes, use the v-bind directive, almost always written with its colon shorthand: :src, :class, :disabled. Vue evaluates the expression on the right and keeps the attribute in sync as the underlying data changes. class and style get special treatment: you can bind an object or array to :class and Vue toggles individual class names based on truthy values.
Dynamic Attributes and Classes
<script setup>
import { ref, computed } from 'vue'
const avatarUrl = ref('/images/ada.png')
const isOnline = ref(true)
const statusClass = computed(() => ({
'status-online': isOnline.value,
'status-offline': !isOnline.value
}))
</script>
<template>
<img :src='avatarUrl' alt='User avatar' />
<span :class='statusClass'>{{ isOnline ? 'Online' : 'Offline' }}</span>
<button :disabled='!isOnline'>Message</button>
</template>Rendering Raw HTML with v-html
Because mustache interpolation escapes its output, printing '<strong>bold</strong>' would show the literal tags as text rather than making the word bold. When you genuinely need to inject a string of HTML markup -- content from a trusted CMS field, for instance -- use the v-html directive instead. It replaces the element's inner content with the raw, unescaped HTML you provide.
Injecting Trusted Markup
<script setup>
import { ref } from 'vue'
const articleBody = ref('<p>This paragraph includes <em>emphasis</em> and a <a href=\"/more\">link</a>.</p>')
</script>
<template>
<article v-html='articleBody'></article>
</template>Directive Quick Reference
Exercise: Vue Templates
What is the main difference between v-if and v-show?