Chapter 17: Vue Templates
Vue Templates in Vue 3 (the way almost everyone builds UIs in 2026). This is the heart of how Vue feels “HTML on steroids” and makes building interactive pages feel natural.
What Exactly is a “Vue Template”?
In Vue, the template is the HTML-like structure that describes what the user sees on the screen. It’s the part of a Vue component (usually inside a .vue file) that gets turned into real DOM elements.
Key facts from the official Vue 3 guide (vuejs.org/guide/essentials/template-syntax):
- Vue uses an HTML-based template syntax
- It lets you declaratively bind the rendered DOM to your JavaScript data & logic
- Templates are valid HTML — browsers & parsers can read them
- Vue compiles them at build time (with Vite) into highly-optimized JavaScript render functions
- Thanks to reactivity, Vue only updates the minimal parts of the DOM when data changes
So when you write:
|
0 1 2 3 4 5 6 |
<div>Hello {{ name }}</div> |
Vue compiles it roughly to something like:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
// pseudo internal render function function render(_ctx, _cache) { return createElementVNode("div", null, [ createTextVNode("Hello "), createTextVNode(toDisplayString(_ctx.name), 1 /* TEXT */) ]) } |
But you never see or write that — you just write nice HTML + special syntax.
Where Do Templates Live in Vue 3?
In a typical Single File Component (.vue file) — the modern standard:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<!-- MyComponent.vue --> <template> <!-- This is the Vue template --> <div class="container"> <h1>Welcome, {{ userName }}</h1> <button @click="greet">Say Hi</button> </div> </template> <script setup> import { ref } from 'vue' const userName = ref('Rahul from Hyderabad') function greet() { alert('Namaste! 🌶️') } </script> <style scoped> .container { padding: 2rem; text-align: center; } </style> |
- <template> → only one root element allowed (but can be <template> itself in Vue 3 for fragments)
- <script setup> → modern logic (no export default)
- <style scoped> → CSS only for this component
Other ways (less common now but good to recognize):
- Inline string template (rare in SFC projects)
|
0 1 2 3 4 5 6 7 8 9 |
export default { template: `<button @click="count++">Count: {{ count }}</button>`, data() { return { count: 0 } } } |
- Point to external <template id=”…”> in HTML
- Render functions / JSX (advanced, when you want full JS control)
But 99% of Vue 3 code in 2026 uses the <template> block in .vue files.
Core Parts of Vue Template Syntax
Vue extends normal HTML with these special features:
1. Text Interpolation – {{ }} (Mustache syntax)
|
0 1 2 3 4 5 6 |
<p>Hello {{ userName }}! You have {{ todos.length }} tasks.</p> |
- Anything inside {{ }} is a JavaScript expression
- Auto-converts to string
- Safe by default (escapes HTML)
2. Directives – v- attributes (the superpowers)
|
0 1 2 3 4 5 6 7 8 9 10 |
<input v-model="message" /> <!-- two-way binding --> <button @click="increment">+1</button> <!-- event listener --> <div v-if="isLoggedIn">Welcome back</div> <!-- conditional --> <li v-for="item in items" :key="item.id">{{ item.name }}</li> <!-- loop --> <img :src="imageUrl" alt="Product" /> <!-- dynamic attribute --> |
Common directives we’ll cover more in other lessons:
- v-bind / : → bind attributes / props
- v-on / @ → events
- v-model → forms
- v-if / v-else / v-show
- v-for
- v-text / v-html (careful with last one – XSS risk)
3. Dynamic Arguments (square brackets)
|
0 1 2 3 4 5 6 7 |
<button @[eventName]="handler">Click</button> <!-- eventName = ref('click') or 'mouseover' etc. --> |
4. JavaScript Expressions Allowed (but keep them simple!)
|
0 1 2 3 4 5 6 7 8 |
{{ isAdult ? 'Adult' : 'Minor' }} {{ formatDate(birthday) }} <div :class="['card', isPremium ? 'premium' : 'basic']"> |
Rule of thumb: If logic gets complex → move it to computed or method, not template.
5. <template> as wrapper (no extra DOM node)
|
0 1 2 3 4 5 6 7 8 9 |
<template v-if="showModal"> <div class="overlay"></div> <div class="modal">Content</div> </template> |
→ No useless <div> wrapper when condition false
Full Mini Example – Todo Header (Putting It Together)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<template> <header class="todo-header"> <h1 :class="{ urgent: remaining === 0 }"> My Todos ({{ remaining }} remaining) </h1> <input v-model.trim="newTask" placeholder="What needs to be done?" @keyup.enter="addTask" /> <small v-if="newTask.length > 50" class="warning"> Task is too long! </small> </header> </template> <script setup> import { ref, computed } from 'vue' const newTask = ref('') const todos = ref([ { text: 'Learn Vue templates', done: true }, { text: 'Build something cool', done: false } ]) const remaining = computed(() => todos.value.filter(t => !t.done).length) function addTask() { if (!newTask.value.trim()) return todos.value.push({ text: newTask.value.trim(), done: false }) newTask.value = '' } </script> <style scoped> .todo-header { padding: 1.5rem; background: #f0f9ff; border-radius: 12px; } h1 { margin: 0 0 1rem; } .urgent { color: #ef4444; } .warning { color: #dc2626; font-size: 0.9rem; } input { width: 100%; padding: 0.8rem; font-size: 1.1rem; } </style> |
Quick Summary Table – Template Essentials
| Feature | Syntax Example | Purpose / When to Use |
|---|---|---|
| Text interpolation | {{ fullName }} | Display dynamic text |
| Dynamic attribute | :src=”imageUrl” | Bind src, href, id, data-*, etc. |
| Class binding | :class=”{ active: isActive }” | Toggle classes conditionally |
| Style binding | :style=”{ color: textColor }” | Inline styles dynamically |
| Event listener | @click=”increment” | Handle clicks, keyup, submit… |
| Conditional rendering | v-if=”show” / v-show=”visible” | Show/hide elements |
| List rendering | v-for=”item in items” | Repeat elements for arrays/objects |
| Two-way form binding | v-model=”inputValue” | Forms & inputs |
| Wrapper (no DOM node) | <template v-if=”…”> | Group elements conditionally |
Pro Tips from 2026 Hyderabad Vue Scene
- Keep templates readable — if it’s longer than 10–15 lines or has complex expressions → extract to components or computed
- Always use :key in v-for
- Prefer v-bind() in <style scoped> for reactive CSS variables (dark mode, themes)
- Use Tailwind? Templates love it: :class=”{ ‘bg-blue-600’: active, ‘text-white’: active }”
- No build step? Vue still works with <script src=”vue.global.js”> + <div id=”app”> template in HTML
Practice: Take any small UI (pricing card, profile header, form) → write just the <template> part first, then add reactivity.
Any part unclear? Want to compare templates vs render functions / JSX? Or deep dive into one directive (v-for, v-model…)? Or how templates compile under the hood?
Just say — we’ll go as deep as you want step by step 🚀
Happy templating from Hyderabad! 💙
