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

Text Interpolation

vue
<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):

vue
<span v-text="message"></span>

v-html renders raw HTML—XSS risk if content comes from users:

vue
<!-- 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:

vue
<button :disabled="isLoading">Save</button>

Object form—multiple attributes at once:

vue
<div v-bind="{ id: 'box', class: 'card', title: 'Tip' }"></div>

Dynamic argument (advanced):

vue
<a :[attributeName]="value">Link</a>

Class and Style Binding

Object class map:

vue
<p :class="{ active: isActive, 'text-danger': hasError }">Status</p>

Array of classes:

vue
<p :class="[baseClass, isActive ? 'active' : '']">Item</p>

Inline style object:

vue
<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:

vue
<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:

vue
<p v-show="isVisible">Toggle visibility</p>
v-ifv-show
DOMAdd/removeAlways present
CostHigher toggle if frequentCheaper frequent toggle
UseRare conditionsFrequent show/hide

<template v-if> groups without extra wrapper:

vue
<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:

vue
<!-- Avoid for reorderable lists -->
<li v-for="(todo, index) in todos" :key="index">

Loop object properties:

vue
<li v-for="(value, key) in user" :key="key">
  {{ key }}: {{ value }}
</li>

<template v-for> for multiple roots per item:

vue
<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 @:

vue
<button @click="save">Save</button>
<button @click="count++">Inline</button>
<button @click="onSubmit($event)">With event</button>

Method in script:

vue
<script setup lang="ts">
function onSubmit(event: Event) {
  event.preventDefault();
  // handle form
}
</script>

Event Modifiers

vue
<form @submit.prevent="onSubmit">
  <button @click.stop="onClick">No bubble</button>
  <input @keyup.enter="submit" />
  <button @click.once="init">Once only</button>
</form>
ModifierEffect
.preventevent.preventDefault()
.stopevent.stopPropagation()
.onceHandler runs once
.enterKey is Enter

Chain modifiers: @click.stop.prevent.

v-model Preview

Two-way binding on inputs—full chapter in Forms and v-model:

vue
<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.