Vue.js: Template Syntax

Last updated: 2026-10-20

Vue's template syntax is a declarative extension of HTML — it adds "directives" and "interpolation" on top of plain HTML so you can render data into the DOM. The whole syntax is about 90% identical to HTML, so anyone who knows HTML can get productive in 30 minutes.

Vue templates revolve around three actions: interpolation (display data) + directives (bind attributes/events) + expressions (run JS). This lesson covers the standard way to write all three.

Related Directives:v-text v-html v-once

1. What You'll Learn


2. A Product Card Rendering Requirement

(1) The Pain: 30 Products, Copy-Paste 30 Times?

Alice is building an e-commerce admin. She needs to display 30 product cards. Her first approach:

HTML
<!-- Copied and pasted 30 times — a nightmare... -->
<div class="product-card">
  <h3>iPhone 15 Pro</h3>
  <p>Price: $999</p>
  <button>Edit</button>
</div>
<div class="product-card">
  <h3>MacBook Pro</h3>
  <p>Price: $2499</p>
  <button>Edit</button>
</div>
<!-- ... and 28 more ... -->

Product manager Charlie says, "change the price format to include a currency symbol":

"Alice, you can't hand-edit 30 files. What if there are 5,000 products next month? We need dynamic templates."

(2) The Vue Template Solution: 1 Component, 30 Data Records

5 lines of template × 30 products = zero copy-paste. When a name or price changes, Vue updates the DOM automatically.

(3) The Payoff

With Vue templates:


3. Interpolation: Mustache {{ }}

(1) The 4 Interpolation Forms

Form Effect Example
{{ var }} Displays a variable's value <p>{{ username }}</p> → Alice
{{ expr }} Displays the result of a JS expression <p>{{ count + 1 }}</p> → 6
{{ fn() }} Calls a function and shows its return value <p>{{ formatDate(date) }}</p> → 2026-07-02
{{ obj.prop }} Accesses an object property <p>{{ user.name }}</p> → Alice

(2) 5 Key Interpolation Behaviors

(3) Interpolation vs v-text

▶ Example: Multiple Interpolation Forms

▶ Try it Yourself

Output:

TEXT
Five lines of text — Variable: Alice, Expression: 11, Passed (≥60) (the v-else line stays hidden), Date: 2026-10-18, and User: Alice.
TEXT
Variable: Alice
Expression: 11
Passed (≥60)
Date: 2026-10-18
User: Alice

(4) 📊 Template vs HTML Cheat Sheet

Element HTML Vue Notes
Static text <p>Hello</p> <p>{{ msg }}</p> Make it dynamic
Static attribute <img src="x.jpg"> <img :src="url"> Make it dynamic
Static class <div class="box"> <div :class="cls"> Make it dynamic
Static style <div style="color: red"> <div :style="sty"> Make it dynamic
Click event <button onclick="fn()"> <button @click="fn"> Switch to Vue
Conditional rendering None <div v-if="ok"> Vue only
List rendering None <div v-for="i in list"> Vue only

4. Text Directives: v-text / v-html / v-once

(1) Comparing the Three Directives

Directive Purpose Use case Safety
{{ }} interpolation Text interpolation Default choice ✅ Safe
v-text Sets the element's textContent Directive form of interpolation ✅ Safe
v-html Sets the element's innerHTML Rendering rich text (use with care) ⚠️ XSS risk
v-once Renders once, never updates afterwards Static optimization ✅ Safe

(2) The v-html Warning

(3) v-once Performance Optimization


5. Attribute Binding: v-bind and the : Shorthand

(1) v-bind Basics

(2) class and style Binding (Key)

(3) style Binding

▶ Example: 5 v-bind Forms

▶ Try it Yourself

Output:

TEXT
Five numbered lines. The images load from the placeholder URL and get alt="Logo";
the first span carries class="active", the second class="active error";
the link points to https://example.com/users/1001.
TEXT
1. Basic: [image]
2. Dynamic attribute: [image]
3. Object syntax: A        → class="active"
4. Array syntax: B         → class="active error"
5. String concatenation: Profile → https://example.com/users/1001

6. Event Binding: v-on and the @ Shorthand

(1) v-on Basics

(2) Common Event Modifiers (9)

(3) Modifier Chains

▶ Example: 5 v-on Forms

▶ Try it Yourself

Output:

TEXT
Five controls: clicking 1. Click logs clicked; 2.
+ (count: 0) increments the label to count: 1 on each click; 3.
Delete Item A logs the id and event object; 4. Save logs Save button clicked;
pressing Ctrl+Enter in the input logs Ctrl+Enter submitted.
TEXT
[ 1. Click ]
[ 2. + (count: 0) ]
[ 3. Delete Item A ]
[ 4. Save (stop propagation + default behavior) ]
[ 5. Ctrl+Enter to submit          ]

7. Expression Limits (No Statements)

(1) Template Expressions vs JS Statements

(2) Expressions vs Computed Properties

Scenario Use an expression Use a computed property
Simple calculation (1-2 operators) ✅ ❌
Complex logic (multiple steps, loops) ❌ ✅
Needs caching ❌ ✅
Needs parameters ✅ ❌ (use a method instead)

8. Edge-Case Directives: v-pre / v-cloak

(1) v-pre: Skip Compilation

When to use: displaying Vue template syntax itself (teaching material, documentation sites).

(2) v-cloak: Hide Before Compilation

When to use: preventing users from seeing {{ message }} flash before compilation.


9. Complete Example: Dynamic Product Card

▶ Example: Basic Product Card

▶ Try it Yourself

Output:

TEXT
A card showing iPhone 15 Pro, $999, and a Only 5 left badge styled with the low-stock class.
The Add to Cart button is enabled (stock is 5, not 0);
clicking it logs Added iPhone 15 Pro to the console.
TEXT
iPhone 15 Pro
$999
Only 5 left
[ Add to Cart ]

10. Common Mistakes at a Glance

Sections 1-8 covered interpolation, v-text/v-html, v-bind, v-on and expression limits. Here are the most common mistakes in one table — come back to it whenever a template misbehaves.

(1) 📊 5 Common Mistakes

Mistake Symptom Fix
Forgetting .value Template uses {{ count }}, JS uses count.value The template unwraps automatically; JS needs .value
Writing if/for inside {{ }} Compile error Use the v-if / v-for directives
v-html XSS User input with <script> executes Sanitize with DOMPurify
Inline handler without $event The event object never arrives Pass it explicitly: @click="fn($event)"
Wrong modifier order Propagation is not stopped Put .stop before .prevent (as needed)

Related Directives:v-text v-html v-once

❓ FAQ

Q What is the difference between {{ }} and v-text?
A The effect is the same — both set the element's textContent. The difference is that {{ }} can be mixed with static text (<p>Hi, {{ name }}</p>), while v-text must own the whole element (<p v-text="msg"></p>). Use {{ }} — it is more flexible.
Q Is v-html safe?
A No. v-html parses the string as HTML, so a malicious user can inject <script> and attack your site. Unless you trust the data source 100% (for example, Markdown you rendered yourself), use {{ }} interpolation or run the value through DOMPurify.sanitize() first.
Q In what order do chained v-on modifiers execute?
A Left to right. For example, @click.stop.prevent calls stopPropagation() first, then preventDefault().
Q v-bind has a shorthand — does v-on?
A v-bind's shorthand is : (drop v-bind), and v-on's shorthand is @ (recommended). Both have been official since Vue 2, and IDE highlighting and autocomplete support them.
Q Can I write if/else in a template?
A No. Template expressions must return a value, and if/for are statements, not expressions. Use the v-if / v-else-if / v-else directives for conditional rendering.
Q How do I switch multiple classes dynamically with v-bind?
A Use object syntax :class="{ active: isActive, 'text-danger': hasError }", or array syntax :class="[activeClass, errorClass]". You can mix them: :class="[isActive && 'active', { 'error': hasError }]".
Q How do I listen for Ctrl+S?
A Use a system modifier: @keyup.ctrl.s="save" or @keydown.ctrl.s.prevent="save" (adding .prevent blocks the browser's save dialog). Vue 3 also has the .exact modifier, so @click.ctrl.exact requires Ctrl and nothing else.

📖 Summary


📝 Exercises

  1. Basic (⭐) Write a Vue 3 component that renders a user card with:

    • Username (interpolation)
    • Avatar (v-bind)
    • A "Follow" button (v-on)
    • Online/offline status (dynamic class toggling)

    Use this data: the user object { name: 'Alice', avatar: 'alice.jpg', online: true }

  2. Intermediate (⭐⭐) Build a simple Todo list:

    • An input (no v-model yet — simulate it with v-bind:value + @input)
    • An add button (@click + expression)
    • List rendering (v-for, covered in the next lesson)
    • A delete button on each row (@click + argument passing)

    Data: const todos = ref(['Learn Vue', 'Build app', 'Deploy'])

  3. Challenge (⭐⭐⭐) Write a complete product detail card component that supports:

    1. 5 product status badges (on sale / out of stock / pre-order / promotion / delisted)
    2. A different class color for each of the 5 statuses (batch-bound with object syntax)
    3. Quantity +/- buttons (@click increment/decrement)
    4. Disabling the "Add to Cart" button when quantity ≥ stock (:disabled dynamic)
    5. At least 3 event modifiers (@click.stop / @submit.prevent and so on)
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏