Template Syntax and Directives
Introduction
Vue templates extend HTML with directives—special attributes prefixed with v- that bind data, conditionally render, loop lists, and handle events. This chapter covers interpolation, v-bind, v-if, v-for, v-on, and common modifiers you will use in every component.
Prerequisites
- First Vue Application and SFC
- Familiarity with HTML basics
Text Interpolation
<template>
<p>{{ message }}</p>
<p>{{ count + 1 }}</p>
<p>{{ ok ? "Yes" : "No" }}</p>
</template>Expressions inside {{ }} are JavaScript—no statements (if, for).
v-text sets text content (rare vs mustache):
<span v-text="message"></span>v-html renders raw HTML—XSS risk if content comes from users:
<!-- Only trusted HTML -->
<div v-html="trustedHtml"></div>Warning
Never use v-html with unsanitized user input.
v-bind (Attributes)
Shorthand ::
Boolean attributes bind to truthy/falsy:
<button :disabled="isLoading">Save</button>Object form—multiple attributes at once:
<div v-bind="{ id: 'box', class: 'card', title: 'Tip' }"></div>Dynamic argument (advanced):
<a :[attributeName]="value">Link</a>Class and Style Binding
Object class map:
<p :class="{ active: isActive, 'text-danger': hasError }">Status</p>Array of classes:
<p :class="[baseClass, isActive ? 'active' : '']">Item</p>Inline style object:
<p :style="{ color: textColor, fontSize: size + 'px' }">Styled</p>See Class, Style, and Transitions for deeper patterns.
v-if, v-else-if, v-else vs v-show
v-if removes elements from DOM when false:
<p v-if="score >= 90">Grade A</p>
<p v-else-if="score >= 60">Pass</p>
<p v-else>Retake</p>v-show toggles display: none—element stays in DOM:
<p v-show="isVisible">Toggle visibility</p>| v-if | v-show | |
|---|---|---|
| DOM | Add/remove | Always present |
| Cost | Higher toggle if frequent | Cheaper frequent toggle |
| Use | Rare conditions | Frequent show/hide |
<template v-if> groups without extra wrapper:
<template v-if="loggedIn">
<h2>Dashboard</h2>
<p>Welcome back.</p>
</template>v-for and Keys
Loop arrays:
:key must be a stable unique id—not array index when list reorders:
<!-- Avoid for reorderable lists -->
<li v-for="(todo, index) in todos" :key="index">Loop object properties:
<li v-for="(value, key) in user" :key="key">
{{ key }}: {{ value }}
</li><template v-for> for multiple roots per item:
<template v-for="todo in todos" :key="todo.id">
<dt>{{ todo.text }}</dt>
<dd>{{ todo.done ? "Done" : "Open" }}</dd>
</template>Tip
Do not use v-if and v-for on the same element—filter with computed or wrap template.
v-on (Events)
Shorthand @:
<button @click="save">Save</button>
<button @click="count++">Inline</button>
<button @click="onSubmit($event)">With event</button>Method in script:
<script setup lang="ts">
function onSubmit(event: Event) {
event.preventDefault();
// handle form
}
</script>Event Modifiers
<form @submit.prevent="onSubmit">
<button @click.stop="onClick">No bubble</button>
<input @keyup.enter="submit" />
<button @click.once="init">Once only</button>
</form>| Modifier | Effect |
|---|---|
.prevent | event.preventDefault() |
.stop | event.stopPropagation() |
.once | Handler runs once |
.enter | Key is Enter |
Chain modifiers: @click.stop.prevent.
v-model Preview
Two-way binding on inputs—full chapter in Forms and v-model:
<input v-model="search" placeholder="Search" />
<p>You typed: {{ search }}</p>Practice: Todo List Shell
Later chapters replace visibleTodos() with computed for caching—Computed and Watch.
FAQ
Mustache vs v-text?
{{ }} is standard; v-text overwrites child nodes.
v-if vs v-show for modals?
v-if if modal mounts heavy children rarely; v-show if toggled often.
Why matters?
Vue reuses DOM nodes efficiently; wrong keys cause wrong row state after reorder.
Can I use v-for on components?
Yes—:key on component tag; pass todo as prop.
Template expressions limits?
No console.log, if, or var—use methods or computed.
Same as Angular directives?
Similar idea (*ngIf / v-if)—syntax differs.