Table of Contents
- What Are Vue.js Directives?
- Essential Vue Directives
- v-text: Update Element Text Content
- v-html: Render HTML Content
- v-bind: Dynamically Bind Attributes
- v-on: Handle Events
- v-model: Two-Way Data Binding
- v-for: Render Lists
- v-if / v-else / v-else-if: Conditional Rendering
- v-show: Toggle Element Visibility
- v-pre: Skip Compilation
- v-cloak: Hide Uncompiled Templates
- v-once: Render Once
- Conclusion
- References
What Are Vue.js Directives?
In Vue.js, a directive is a special attribute prefixed with v- that tells Vue to apply specific behavior to the DOM element it’s attached to. Directives are reactive: they automatically update the DOM when the underlying data changes, making your app dynamic without manual intervention.
For example, the v-text directive sets the text content of an element to a data property, and if that property changes, the text updates instantly.
Directives can also accept arguments (e.g., v-bind:href binds the href attribute) and modifiers (e.g., v-on:submit.prevent prevents the default form submission behavior) to customize their behavior. Many directives also have shorthand syntax to reduce boilerplate (e.g., : for v-bind and @ for v-on).
Essential Vue Directives
v-text: Update Element Text Content
Purpose: Sets the text content of an element to a reactive data property.
Syntax:
<p v-text="message"></p>
Example:
<div id="app">
<p v-text="greeting"></p>
</div>
<script>
new Vue({
el: '#app',
data: {
greeting: 'Hello, Vue Directives!'
}
});
</script>
Output:
Hello, Vue Directives!
Notes:
- Shorthand: None (use
{{ message }}for interpolation instead, which is more common for text content). v-textreplaces the entire text content of the element, whereas interpolation ({{ }}) inserts text into the element.
v-html: Render HTML Content
Purpose: Renders raw HTML content into an element (instead of plain text).
Syntax:
<div v-html="rawHtml"></div>
Example:
<div id="app">
<div v-html="richText"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
richText: '<strong>Hello, Vue!</strong> This is <em>HTML</em> content.'
}
});
</script>
Output:
Hello, Vue! This is HTML content.
Notes:
- Security Warning: Never use
v-htmlwith untrusted content (e.g., user input) as it can lead to XSS attacks. Only use it for trusted HTML. v-htmloverwrites the element’s inner HTML, so any existing content will be replaced.
v-bind: Dynamically Bind Attributes
Purpose: Dynamically binds an HTML attribute to a data property. Use it to set attributes like src, href, class, or style reactively.
Syntax:
<img v-bind:src="imageUrl">
<a v-bind:href="linkUrl">Click me</a>
Shorthand: : (replace v-bind: with :)
<img :src="imageUrl">
<a :href="linkUrl">Click me</a>
Example: Binding Classes
You can bind classes conditionally using an object:
<div id="app">
<p :class="{ active: isActive, 'text-danger': hasError }">
This paragraph has dynamic classes.
</p>
</div>
<script>
new Vue({
el: '#app',
data: {
isActive: true,
hasError: false
}
});
</script>
Resulting HTML:
<p class="active">This paragraph has dynamic classes.</p>
Notes:
- Use
v-bindfor any attribute that needs to update when data changes. - Supports expressions, arrays, and objects for complex bindings (e.g.,
:class="[activeClass, errorClass]").
v-on: Handle Events
Purpose: Attaches event listeners to elements (e.g., click, submit, input) and triggers methods or inline expressions when the event occurs.
Syntax:
<button v-on:click="handleClick">Click Me</button>
<form v-on:submit="handleSubmit">Submit</form>
Shorthand: @ (replace v-on: with @)
<button @click="handleClick">Click Me</button>
<form @submit="handleSubmit">Submit</form>
Example with Method
<div id="app">
<p>Count: {{ count }}</p>
<button @click="incrementCount">Increment</button>
</div>
<script>
new Vue({
el: '#app',
data: {
count: 0
},
methods: {
incrementCount() {
this.count++;
}
}
});
</script>
Output: A button that increments the count when clicked.
Modifiers: Add modifiers to alter event behavior (e.g., .prevent to stop default actions, .stop to stop propagation):
<form @submit.prevent="handleSubmit"> <!-- Prevents default form submission -->
<input type="text">
<button type="submit">Submit</button>
</form>
v-model: Two-Way Data Binding
Purpose: Creates two-way binding between form inputs (e.g., text fields, checkboxes) and data properties. When the input changes, the data updates, and vice versa.
Syntax:
<input v-model="username" type="text">
Example:
<div id="app">
<p>Hello, {{ username }}!</p>
<input v-model="username" placeholder="Enter your name">
</div>
<script>
new Vue({
el: '#app',
data: {
username: ''
}
});
</script>
Behavior: Typing in the input updates username, and username is displayed in the paragraph.
Modifiers:
.trim: Trims whitespace from the input value..number: Converts the input to a number..lazy: Updates data only onchangeevent (instead ofinput).
<input v-model.trim="username"> <!-- Trims input -->
<input v-model.number="age" type="text"> <!-- Converts to number -->
<input v-model.lazy="searchQuery"> <!-- Updates on blur/enter -->
Supported Elements: Works with <input>, <textarea>, <select>, checkboxes, and radio buttons.
v-for: Render Lists
Purpose: Renders a list of elements by iterating over an array or object.
Syntax for Arrays:
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
:keyis required for performance and to help Vue track list items uniquely (use a unique identifier likeid).
Example with Array
<div id="app">
<h3>Todo List</h3>
<ul>
<li v-for="(todo, index) in todos" :key="index">
{{ index + 1 }}. {{ todo }}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
todos: ['Learn Vue directives', 'Build a demo app', 'Practice!']
}
});
</script>
Output:
- Learn Vue directives
- Build a demo app
- Practice!
Iterating Over Objects:
<div v-for="(value, key) in user" :key="key">
{{ key }}: {{ value }}
</div>
Notes:
- Always use
:keywithv-forto avoid rendering issues. - Avoid using
indexas a key for lists that can be reordered (use unique IDs instead).
v-if / v-else / v-else-if: Conditional Rendering
Purpose: Conditionally renders elements based on a truthy/falsy expression. Unlike v-show, v-if unmounts the element from the DOM when the condition is false.
Syntax:
<p v-if="isLoggedIn">Welcome back!</p>
<p v-else>Please log in.</p>
Example with v-else-if
<div id="app">
<p v-if="score >= 90">A Grade</p>
<p v-else-if="score >= 70">B Grade</p>
<p v-else-if="score >= 50">C Grade</p>
<p v-else>Fail</p>
</div>
<script>
new Vue({
el: '#app',
data: {
score: 75 // Renders "B Grade"
}
});
</script>
Notes:
v-elseandv-else-ifmust immediately follow av-iforv-else-ifelement (no siblings in between).- Use
v-iffor conditions that rarely change (since unmounting/mounting is costly). For frequent toggling, usev-show.
v-show: Toggle Element Visibility
Purpose: Toggles element visibility by setting the display CSS property (hides with display: none when false, shows with original display value when true).
Syntax:
<p v-show="isVisible">This is visible if isVisible is true.</p>
Example:
<div id="app">
<button @click="toggleVisibility">Toggle</button>
<p v-show="isVisible">Hello, Vue!</p>
</div>
<script>
new Vue({
el: '#app',
data: {
isVisible: true
},
methods: {
toggleVisibility() {
this.isVisible = !this.isVisible;
}
}
});
</script>
v-if vs. v-show:
v-if: Removes/Adds element from DOM (higher toggle cost, lower initial render cost if condition is false).v-show: TogglesdisplayCSS (lower toggle cost, higher initial render cost as element is always in DOM).
v-pre: Skip Compilation
Purpose: Skips Vue compilation for the element and its children. Useful for displaying raw mustache syntax ({{ }}) without rendering data.
Syntax:
<p v-pre>{{ This will not be compiled! }}</p>
Output:
{{ This will not be compiled! }}
v-cloak: Hide Uncompiled Templates
Purpose: Hides uncompiled mustache bindings until Vue finishes compiling the template. Prevents flashing {{ message }} before data loads.
Syntax:
<p v-cloak>{{ message }}</p>
CSS Requirement: Add this CSS to your stylesheet to hide elements with v-cloak until compilation:
[v-cloak] {
display: none;
}
Example:
<style>
[v-cloak] { display: none; }
</style>
<div id="app">
<p v-cloak>{{ message }}</p>
</div>
<script>
// Simulate delayed data load
setTimeout(() => {
new Vue({
el: '#app',
data: {
message: 'Compiled!'
}
});
}, 1000);
</script>
Behavior: The paragraph remains hidden for 1 second, then shows “Compiled!” (no flash of {{ message }}).
v-once: Render Once
Purpose: Renders the element once and then treats it as static (no further updates, even if data changes).
Syntax:
<p v-once>{{ initialMessage }}</p>
Example:
<div id="app">
<p v-once>Initial value: {{ count }}</p>
<p>Current value: {{ count }}</p>
<button @click="count++">Increment</button>
</div>
<script>
new Vue({
el: '#app',
data: {
count: 0
}
});
</script>
Behavior: The “Initial value” paragraph always shows 0, while “Current value” updates with each click.
Conclusion
Vue.js directives are the building blocks of dynamic UIs, enabling you to bind data, handle events, conditionally render elements, and more—all with minimal code. By mastering essential directives like v-model, v-for, v-bind, and v-on, you’ll be able to create interactive and responsive applications quickly.
Remember, practice is key! Experiment with these directives in small projects (e.g., a todo app, a form with validation) to solidify your understanding. As you progress, explore advanced directives and modifiers to unlock even more functionality.