Vue.js Template Syntax
Introduction
Vue.js template syntax is a powerful feature that allows you to declaratively render DOM elements based on your JavaScript data. Unlike traditional templating systems, Vue's template syntax is valid HTML that can be parsed by browsers and HTML parsers. This syntax provides special directives and features to bind data, handle events, and create dynamic interfaces with minimal effort.
In this guide, we'll explore Vue.js template syntax fundamentals, including text interpolation, directives, event handling, and conditional rendering. By the end, you'll have a solid understanding of how to leverage Vue's template system to build interactive web applications.
Text Interpolation
The most basic form of data binding in Vue is text interpolation using the "Mustache" syntax (double curly braces).
Basic Text Interpolation
<template>
<div>
<p>Message: {{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: "Hello Vue!"
}
}
}
</script>
Output:
Message: Hello Vue!
The mustache tag will be replaced with the value of the message
property from the corresponding component instance. It will also be updated whenever the message
property changes.
Using JavaScript Expressions
Vue.js supports JavaScript expressions inside the interpolation:
<template>
<div>
<p>{{ message.split('').reverse().join('') }}</p>
<p>{{ isActive ? 'Active' : 'Inactive' }}</p>
<p>{{ number + 1 }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: "Hello Vue!",
isActive: true,
number: 10
}
}
}
</script>
Output:
!euV olleH
Active
11
Only single expressions are supported. Statements like if
or for
loops won't work in mustaches.
Directives
Directives are special attributes with the v-
prefix. They apply special reactive behavior to the rendered DOM.
v-bind
The v-bind
directive is used to dynamically bind attributes to expressions.
<template>
<div>
<a v-bind:href="url">Link to Vue.js</a>
<!-- Shorthand syntax -->
<a :href="url">Link to Vue.js (shorthand)</a>
<button :disabled="isButtonDisabled">Button</button>
</div>
</template>
<script>
export default {
data() {
return {
url: "https://vuejs.org",
isButtonDisabled: true
}
}
}
</script>
In this example, the href
attribute is dynamically bound to the url
value, and the button's disabled
attribute is controlled by the isButtonDisabled
data property.
v-model
The v-model
directive creates two-way data binding on form inputs:
<template>
<div>
<input v-model="message" placeholder="Edit me">
<p>The message is: {{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: ""
}
}
}
</script>
When you type in the input field, the message
property updates in real-time, and the paragraph text updates accordingly.
v-if, v-else-if, and v-else
These directives conditionally render elements based on expressions:
<template>
<div>
<h2>User Status</h2>
<div v-if="userType === 'admin'">
Admin Panel
</div>
<div v-else-if="userType === 'moderator'">
Moderator Panel
</div>
<div v-else>
Regular User
</div>
</div>
</template>
<script>
export default {
data() {
return {
userType: "admin"
}
}
}
</script>
Only the element that satisfies the condition will be rendered. In this example, since userType
is "admin", only the Admin Panel will be shown.
v-show
The v-show
directive is similar to v-if
but instead of removing the element from the DOM, it toggles the element's CSS display
property:
<template>
<div>
<h2>Feature Flag Example</h2>
<p v-show="featureEnabled">This feature is enabled!</p>
</div>
</template>
<script>
export default {
data() {
return {
featureEnabled: true
}
}
}
</script>
When featureEnabled
is true
, the paragraph will be visible. When it's false
, the paragraph will still be in the DOM but hidden with display: none
.
v-for
The v-for
directive is used to render a list of items based on an array or object:
<template>
<div>
<h2>Todo List</h2>
<ul>
<li v-for="(todo, index) in todos" :key="todo.id">
{{ index + 1 }}. {{ todo.text }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
todos: [
{ id: 1, text: 'Learn Vue.js' },
{ id: 2, text: 'Build an app' },
{ id: 3, text: 'Deploy to production' }
]
}
}
}
</script>
Output:
Todo List
1. Learn Vue.js
2. Build an app
3. Deploy to production
Always provide a unique :key
attribute with v-for
to help Vue identify each node in the list and reuse/reorder existing elements efficiently.
Event Handling
v-on Directive
The v-on
directive attaches event listeners to elements:
<template>
<div>
<p>Count: {{ count }}</p>
<button v-on:click="increment">Increment</button>
<!-- Shorthand syntax -->
<button @click="decrement">Decrement</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count += 1;
},
decrement() {
this.count -= 1;
}
}
}
</script>
Event Modifiers
Vue provides event modifiers to handle common event behaviors:
<template>
<div>
<!-- Stop propagation -->
<button @click.stop="doThis">Stop Propagation</button>
<!-- Prevent default -->
<form @submit.prevent="onSubmit">Submit</form>
<!-- Chain modifiers -->
<a @click.stop.prevent="doThat">Stop & Prevent</a>
<!-- Only trigger once -->
<button @click.once="doOnce">Click Once</button>
</div>
</template>
Key Modifiers
For keyboard events, Vue offers key modifiers:
<template>
<div>
<input @keyup.enter="submit">
<input @keyup.page-down="onPageDown">
</div>
</template>
Real-world Example: User Profile Form
Let's build a simple user profile form using the template syntax we've learned:
<template>
<div class="profile-form">
<h2>User Profile</h2>
<div class="form-group" :class="{ 'error': !isNameValid }">
<label for="name">Name:</label>
<input
id="name"
v-model="user.name"
@blur="validateName"
placeholder="Enter your name"
>
<p v-if="!isNameValid" class="error-message">Name is required</p>
</div>
<div class="form-group">
<label for="role">Role:</label>
<select id="role" v-model="user.role">
<option v-for="role in availableRoles" :key="role.id" :value="role.value">
{{ role.label }}
</option>
</select>
</div>
<div class="form-group">
<label>Skills:</label>
<div v-for="skill in availableSkills" :key="skill.id" class="checkbox">
<input
type="checkbox"
:id="'skill-' + skill.id"
:value="skill.value"
v-model="user.skills"
>
<label :for="'skill-' + skill.id">{{ skill.label }}</label>
</div>
</div>
<div class="form-group">
<label>Notifications:</label>
<div class="toggle">
<span>Off</span>
<input type="checkbox" v-model="user.notifications">
<span>On</span>
</div>
</div>
<button
@click="saveProfile"
:disabled="!isNameValid || isSaving"
>
{{ isSaving ? 'Saving...' : 'Save Profile' }}
</button>
<div v-if="isSaved" class="success-message">
Profile saved successfully!
</div>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: '',
role: 'developer',
skills: [],
notifications: true
},
availableRoles: [
{ id: 1, value: 'developer', label: 'Developer' },
{ id: 2, value: 'designer', label: 'Designer' },
{ id: 3, value: 'manager', label: 'Manager' }
],
availableSkills: [
{ id: 1, value: 'javascript', label: 'JavaScript' },
{ id: 2, value: 'html', label: 'HTML' },
{ id: 3, value: 'css', label: 'CSS' },
{ id: 4, value: 'vue', label: 'Vue.js' }
],
isNameValid: true,
isSaving: false,
isSaved: false
}
},
methods: {
validateName() {
this.isNameValid = this.user.name.trim() !== '';
},
saveProfile() {
this.validateName();
if (!this.isNameValid) return;
this.isSaving = true;
// Simulate API call
setTimeout(() => {
this.isSaving = false;
this.isSaved = true;
// Hide success message after 3 seconds
setTimeout(() => {
this.isSaved = false;
}, 3000);
console.log('Profile saved:', this.user);
}, 1500);
}
}
}
</script>
This example demonstrates:
- Two-way data binding with
v-model
- Event handling with
@click
and@blur
- Conditional rendering with
v-if
- List rendering with
v-for
- Dynamic attributes with
:class
and:disabled
- Inline expressions in templates
Other Template Features
Template Refs
Template refs provide a way to access DOM elements directly:
<template>
<div>
<input ref="inputField">
<button @click="focusInput">Focus the input</button>
</div>
</template>
<script>
export default {
methods: {
focusInput() {
this.$refs.inputField.focus();
}
}
}
</script>
Computed Properties in Templates
While you can use expressions in templates, for complex logic, computed properties are better:
<template>
<div>
<p>Original message: "{{ message }}"</p>
<p>Reversed message: "{{ reversedMessage }}"</p>
</div>
</template>
<script>
export default {
data() {
return {
message: "Hello Vue.js!"
}
},
computed: {
reversedMessage() {
return this.message.split('').reverse().join('');
}
}
}
</script>
Summary
Vue.js template syntax provides a powerful yet intuitive way to build dynamic user interfaces. We've covered:
- Text interpolation using the mustache syntax (
{{ }}
) - Directives like
v-bind
,v-model
,v-if
, andv-for
- Event handling with
v-on
- Real-world examples showing practical applications
- Advanced features like template refs and computed properties
The template syntax allows Vue to handle all the complex DOM manipulation behind the scenes while you focus on describing what your UI should look like based on state.
Exercises
- Counter App: Create a simple counter with increment, decrement, and reset buttons.
- Todo List: Build a todo list with the ability to add, remove, and mark items as complete.
- Form Validation: Create a form with at least three fields and implement validation using Vue's template syntax.
- Toggle Visibility: Create a button that toggles the visibility of a paragraph using both
v-if
andv-show
. Observe the difference in behavior.
Additional Resources
- Vue.js Official Template Syntax Guide
- Vue.js Form Input Bindings
- Vue.js List Rendering
- Vue.js Computed Properties and Watchers
Learning Vue's template syntax is your first major step toward mastering Vue.js development. As you continue to practice, you'll discover how intuitively you can express complex UI interactions with Vue's declarative approach.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)