Vue.js Template Syntax
Vue.js uses a special syntax inside HTML to connect your data to what appears on the screen. This syntax is called template syntax. It looks like regular HTML but includes extra instructions that Vue understands.
What Is a Template?
A template is the HTML that Vue controls — the part inside your mounted element. Vue reads this HTML, finds the special syntax, and replaces or adjusts it based on your data.
Diagram: Template Processing
Your Template (what you write):
┌────────────────────────────────┐
│ <p>Hello, {{ name }}!</p> │
└────────────────────────────────┘
│
│ Vue processes it
▼
Rendered Output (what the browser shows):
┌────────────────────────────────┐
│ <p>Hello, Maria!</p> │
└────────────────────────────────┘
Text Interpolation — The Double Curly Braces
The most basic template feature is text interpolation. You place a data property name inside double curly braces {{ }}, and Vue replaces it with the actual value.
<div id="app">
<p>Product: {{ productName }}</p>
<p>Price: ${{ price }}</p>
<p>In Stock: {{ available }}</p>
</div>
<script>
Vue.createApp({
data() {
return {
productName: "Laptop Stand",
price: 29,
available: true
};
}
}).mount("#app");
</script>
The browser displays:
Product: Laptop Stand Price: $29 In Stock: true
You Can Use Expressions Inside {{ }}
Vue allows simple JavaScript expressions inside double curly braces — not just variable names.
{{ price * 2 }} → doubles the price
{{ name.toUpperCase() }} → converts name to uppercase
{{ isLoggedIn ? "Hi!" : "Please log in" }} → conditional text
{{ items.length }} → number of items in an array
What You Cannot Put Inside {{ }}
You cannot put full statements (like if blocks or for loops) inside {{ }}. Only single expressions that return a value are allowed.
Valid: {{ count + 1 }}
Valid: {{ user.name }}
Invalid: {{ let x = 5 }} ← statement, not an expression
Invalid: {{ if (x) { ... } }} ← not allowed
The v-text Directive
v-text sets the text content of an element — it does the same thing as {{ }} but as an attribute instead of inline in the HTML.
<p v-text="productName"></p>
<!-- Same result as: -->
<p>{{ productName }}</p>
The difference: v-text replaces the entire content of the element. If the element has existing text inside it, v-text overwrites it.
Rendering Raw HTML — v-html
By default, Vue treats data as plain text and does not interpret HTML tags inside it. If your data contains HTML and you want it rendered as real HTML, use the v-html directive.
data() {
return {
boldMessage: "<strong>Important notice!</strong>"
};
}
<!-- This shows the tag as text: -->
<p>{{ boldMessage }}</p>
Output: <strong>Important notice!</strong>
<!-- This renders the actual bold text: -->
<p v-html="boldMessage"></p>
Output: Important notice! (in bold)
Safety Warning for v-html
Only use v-html with content you fully control. Never use it with content typed by a user. A user could type harmful code that runs in the browser. This type of attack is called XSS (Cross-Site Scripting).
One-Time Rendering — v-once
The v-once directive renders the element one time only. After that first render, Vue stops watching it — even if the data changes, the element stays the same.
<p v-once>Original value: {{ counter }}</p>
<p>Current value: {{ counter }}</p>
<button v-on:click="counter++">Increase</button>
When you click the button, "Current value" increases but "Original value" stays at 0. Use v-once for content that should never change after load — like a document creation date.
Diagram: v-once vs Normal Binding
Initial state: counter = 0 ┌──────────────────────────────────┐ │ v-once: Original value: 0 │ ← frozen forever │ Normal: Current value: 0 │ ← updates with data └──────────────────────────────────┘ After clicking 3 times: counter = 3 ┌──────────────────────────────────┐ │ v-once: Original value: 0 │ ← still 0 │ Normal: Current value: 3 │ ← updated to 3 └──────────────────────────────────┘
Directives — The v- Prefix
Directives are special HTML attributes that start with v-. They give Vue instructions about what to do with an element. You have already seen v-text, v-html, and v-once. Vue provides many more.
Diagram: Anatomy of a Vue Directive
<p v-bind:class="myClass"> │ │ │ │ │ │ │ └── Value: the data property to use │ │ └────────── Argument: what the directive targets │ └──────────────── Directive name └──────────────────── Regular HTML element
Common Directives at a Glance
┌───────────────┬────────────────────────────────────────┐ │ Directive │ What It Does │ ├───────────────┼────────────────────────────────────────┤ │ v-text │ Sets text content │ │ v-html │ Sets inner HTML │ │ v-once │ Renders once, never updates │ │ v-bind │ Binds an attribute to data │ │ v-if │ Shows element if condition is true │ │ v-for │ Repeats element for each item in list │ │ v-on │ Listens for events (clicks, etc.) │ │ v-model │ Two-way binding with form inputs │ └───────────────┴────────────────────────────────────────┘
JavaScript Expressions in Templates
Vue templates support the full power of JavaScript expressions. This makes templates flexible without requiring separate methods for simple calculations.
data() {
return {
firstName: "John",
lastName: "Doe",
cartItems: 3,
priceEach: 15
};
}
<!-- String concatenation -->
<p>{{ firstName + " " + lastName }}</p>
Output: John Doe
<!-- Math -->
<p>Total: ${{ cartItems * priceEach }}</p>
Output: Total: $45
<!-- Ternary -->
<p>{{ cartItems > 0 ? "Items in cart" : "Cart is empty" }}</p>
Output: Items in cart
<!-- Array method -->
<p>{{ firstName.split("").reverse().join("") }}</p>
Output: nhoJ
Template Whitespace and Comments
HTML Comments in Templates
Standard HTML comments (<!-- -->) work inside Vue templates. Vue ignores them when rendering.
<div id="app">
<!-- This heading is the main title -->
<h1>{{ pageTitle }}</h1>
</div>
The Template Root Element
In Vue 3, a component template can have multiple root elements. This is different from Vue 2, which required exactly one root element. Both of these are valid in Vue 3:
<!-- Valid in Vue 3: multiple root elements --> <template> <h1>Title</h1> <p>Description</p> </template>
Full Example: Template Syntax in Action
<div id="app">
<h2>{{ storeName }}</h2>
<p>Items available: {{ itemCount }}</p>
<p>Discount: {{ discount }}% off</p>
<p>You save: ${{ (originalPrice * discount / 100).toFixed(2) }}</p>
<p v-once>Page opened at price: ${{ originalPrice }}</p>
</div>
<script>
Vue.createApp({
data() {
return {
storeName: "Vue Store",
itemCount: 42,
discount: 20,
originalPrice: 100
};
}
}).mount("#app");
</script>
Diagram: Output Mapping
storeName = "Vue Store" → <h2>Vue Store</h2> itemCount = 42 → Items available: 42 discount = 20 → Discount: 20% off 100 * 20 / 100 = 20.00 → You save: $20.00 originalPrice = 100 (frozen) → Page opened at price: $100
Summary
Vue template syntax connects your data to your HTML without writing manual DOM code. Use {{ }} for text output, v-text for setting an element's full text, v-html for rendering real HTML from data, and v-once for content that should never update. Directives — attributes that start with v- — are how Vue adds behavior to HTML elements, and you will learn more of them in the topics ahead.
