Directives
Directives
Level 3 — Directives & Template Features Special attributes provided by Vue, prefixed with
v-, that apply reactive behavior to the rendered HTML DOM.
1. Prerequisites
- Template Syntax — The HTML structure where directives are used.
- Declarative Rendering — The core philosophy directives implement.
2. Term Category
Core Syntax Construct (Template AST Transformations): Directives are specialized XML/HTML template attributes that instruct Vue's template compiler (@vue/compiler-sfc) to transform template nodes into optimized Virtual DOM render functions. Operating at the boundary between static HTML markup and dynamic reactivity, directives abstract DOM operations—attribute binding, event registration, list iteration, structural mounting/unmounting—into declarative attributes. Executed during template compilation and runtime Virtual DOM patching, directives decouple DOM imperative manipulation from component JavaScript execution.
3. Explanation
(1) Design Motivation — "Why did we design this?"
In standard web standards, HTML attributes are static key-value pairs (e.g., <img src="logo.png">). To modify HTML dynamically using vanilla JavaScript, developers historically had to write step-by-step imperative code: querying elements via document.querySelector(), attaching event listeners, and updating attributes manually.
React solves attribute dynamicism by abandoning HTML entirely in favor of JSX, writing JavaScript object expressions directly inside component render trees. Vue took a different architectural direction: preserving standard HTML syntax while enhancing HTML tags with Directives (v-*). Directives signal to Vue's compiler: "Do not treat this attribute string literally; evaluate it as a reactive JavaScript expression and sync the underlying DOM node whenever dependencies change."
(2) Reality Metaphor
Think of an HTML template as a physical blueprint for a electronic circuit board. Standard HTML attributes (id="app", class="card") are like fixed copper traces printed permanently onto the board—they never change once manufactured.
Vue Directives are like smart micro-controllers soldered onto specific circuit pins. A directive like v-bind acts as a dynamic voltage regulator adjusting output dynamically based on sensor input, while v-on acts as a momentary switch waiting for physical button presses. Rather than requiring external wiring changes (imperative JS DOM querying), the micro-controllers manage the pin behavior right on the board blueprint.
(3) Vue Code Examples
Short Snippet
<script setup>
import { ref } from 'vue'
const isHighlighted = ref(true)
const statusMessage = ref('System Operational')
</script>
<template>
<!-- v-bind (:), v-if, and mustache interpolation working in harmony -->
<div :class="{ active: isHighlighted }">
<p v-if="statusMessage">{{ statusMessage }}</p>
</div>
</template>
Fuller Example
<script setup>
import { ref } from 'vue'
const searchQuery = ref('')
const isFilterActive = ref(false)
const items = ref([
{ id: 101, name: 'Server Alpha', status: 'Online' },
{ id: 102, name: 'Server Beta', status: 'Offline' }
])
function toggleFilter() {
isFilterActive.value = !isFilterActive.value
}
</script>
<template>
<div class="system-monitor">
<h2>Cluster Nodes</h2>
<!-- v-model: 2-way form binding directive -->
<input v-model.trim="searchQuery" placeholder="Filter node name..." />
<!-- v-on (@): Event listener directive with click handler -->
<button @click="toggleFilter">
Toggle Filter Mode
</button>
<ul>
<!-- v-for: List iteration directive with mandatory :key -->
<li v-for="node in items" :key="node.id">
<!-- v-bind (:): Dynamic class attribute binding -->
<span :class="['badge', node.status.toLowerCase()]">
{{ node.name }} - {{ node.status }}
</span>
</li>
</ul>
<!-- v-show: Conditional visibility toggle via CSS display -->
<p v-show="isFilterActive" class="filter-notice">
Filter mode active. Showing matching nodes.
</p>
</div>
</template>
<style scoped>
.badge.online { color: #52c41a; }
.badge.offline { color: #ff4d4f; }
.filter-notice { font-style: italic; color: #8c8c8c; }
</style>
4. Common Mistakes & Pitfalls
Mistake 1: Using mustache syntax {{ }} inside HTML attribute values
The mistake: Writing <img src="{{ avatarUrl }}"> inside a Vue component template.
Why it's wrong: Mustache syntax {{ }} works strictly for text content inserted between element tags (<p>{{ text }}</p>). Using mustaches inside tag attributes causes template syntax errors.
Incorrect:
<img src="{{ logoUrl }}"> <!-- ❌ Mustache syntax in HTML attribute! -->
Fix:
<img :src="logoUrl"> <!-- Use v-bind directive shorthand -->
Mistake 2: Confusing dynamic directive arguments with static string identifiers
The mistake: Writing <a v-bind:[href]="linkUrl"> expecting href to be treated as static attribute 'href'.
Why it's wrong: Dynamic arguments inside square brackets :[arg] evaluate arg as a JavaScript variable. If href is undefined in script setup, Vue outputs warnings or sets null attributes.
Incorrect:
<a v-bind:[href]="url">Link</a> <!-- ❌ Evaluates JS variable 'href'! -->
Fix:
<a :href="url">Link</a> <!-- Plain static attribute target -->
Mistake 3: Omitting the v- prefix on built-in Vue directives
The mistake: Writing <div if="isLoggedIn">User Details</div> expecting conditional rendering.
Why it's wrong: Standard HTML attributes like if or for are ignored by Vue's template compiler. Directives MUST start with v- (or valid shorthands :, @, #).
Incorrect:
<div if="isLoggedIn">Welcome</div> <!-- ❌ Ignored plain attribute! -->
Fix:
<div v-if="isLoggedIn">Welcome</div> <!-- Valid Vue directive -->
5. Practice Exercises
Exercise 1: IoT Device Configuration Directive Mapping (IoT)
Scenario: An IoT device control dashboard requires binding telemetry status variables to visual UI cards. You need to identify appropriate directives for attribute binding, event handling, conditional mounting, and input synchronization.
Requirements:
- Bind boolean variable
isDeviceOnlineto disable state of<button>. - Attach click listener calling
rebootDevice()function. - Show warning message ONLY when
deviceTemperature > 80. - Synchronize text input to
deviceLabelref variable.
Answer
Implementation
<script setup>
import { ref } from 'vue'
const isDeviceOnline = ref(true)
const deviceTemperature = ref(85)
const deviceLabel = ref('Edge-Gateway-01')
function rebootDevice() {
console.log('Reboot sequence initiated for:', deviceLabel.value)
}
</script>
<template>
<div class="device-panel">
<!-- 1. v-bind (:disabled) -->
<button :disabled="!isDeviceOnline" @click="rebootDevice">
Reboot Unit
</button>
<!-- 2. v-model 2-way binding -->
<input v-model="deviceLabel" placeholder="Unit Label" />
<!-- 3. v-if conditional mount -->
<p v-if="deviceTemperature > 80" class="warning">
OVERHEAT WARNING: {{ deviceTemperature }}°C
</p>
</div>
</template>
Technical Explanation
- Concept:
:disabled="!isDeviceOnline"usesv-bindshorthand to convert JS booleans into HTML attribute state. - Concept:
@clickusesv-onshorthand to attach DOM event handlers declaratively. - Concept:
v-ifconditionally mounts DOM nodes when threshold expressions evaluate totrue. - Concept:
v-modelmanages two-way input value synchronization.
Exercise 2: Financial Order Book Directive Composition (Finance)
Scenario: A stock trading application displays active market orders. You must construct a template iterating over an order array using list rendering directives and dynamic CSS class binding for order sides (Buy vs Sell).
Requirements:
- Loop over array
ordersusingv-forwith persistent:key. - Apply class
buy-orderwhenorder.side === 'BUY', andsell-orderwhen'SELL'. - Display order total using mustache interpolation.
- Format order row click event passing
order.idto execution handler.
Answer
Implementation
<script setup>
import { ref } from 'vue'
const orders = ref([
{ id: 'ord-101', symbol: 'AAPL', qty: 100, price: 185.50, side: 'BUY' },
{ id: 'ord-102', symbol: 'TSLA', qty: 50, price: 240.00, side: 'SELL' }
])
function selectOrder(id) {
console.log('Selected order:', id)
}
</script>
<template>
<table class="order-book">
<tbody>
<tr
v-for="ord in orders"
:key="ord.id"
:class="{ 'buy-order': ord.side === 'BUY', 'sell-order': ord.side === 'SELL' }"
@click="selectOrder(ord.id)"
>
<td>{{ ord.symbol }}</td>
<td>{{ ord.qty }} @ ${{ ord.price }}</td>
<td>${{ (ord.qty * ord.price).toFixed(2) }}</td>
</tr>
</tbody>
</table>
</template>
Technical Explanation
- Concept:
v-for="ord in orders"loops over data collections in templates. - Concept:
:key="ord.id"provides unique node keys for VDOM patching optimization. - Concept: Object syntax
:class="{ ... }"dynamically evaluates boolean class conditions. - Concept:
@click="selectOrder(ord.id)"passes loop variables directly to event methods.
Exercise 3: Real-Time Network Packet Inspection Directives (Networking)
Scenario: A network analyst dashboard needs to stream network packet captures. You must build a template utilizing v-once for static headers, v-for for packets, and v-show for metadata toggles.
Requirements:
- Render static system metadata block using
v-once. - Render packet list using
v-for. - Toggle detailed packet payload visibility using
v-showbound toshowDetails.
Answer
Implementation
<script setup>
import { ref } from 'vue'
const showDetails = ref(false)
const packets = ref([
{ id: 1, protocol: 'TCP', src: '192.168.1.1', payload: '0x4500003c' },
{ id: 2, protocol: 'UDP', src: '192.168.1.5', payload: '0x01020304' }
])
</script>
<template>
<div class="packet-analyzer">
<!-- Static sub-tree rendered once -->
<div v-once class="header">
<h2>Network Monitor Engine v4.2</h2>
</div>
<button @click="showDetails = !showDetails">Toggle Details</button>
<div v-for="pkt in packets" :key="pkt.id" class="packet-row">
<span>{{ pkt.protocol }} - {{ pkt.src }}</span>
<pre v-show="showDetails">{{ pkt.payload }}</pre>
</div>
</div>
</template>
Technical Explanation
- Concept:
v-oncecaches static subtrees to eliminate re-render overhead. - Concept:
v-showtoggles element display using CSSdisplay: nonewithout unmounting nodes. - Concept: Directives operate declaratively based on reactive state changes.
- Concept: Combining
v-forandv-showmanages dynamic list item UI details cleanly.
6. Related Terms
v-bind— Attribute binding directive.- Template Syntax — Where directives live.
v-for(List Rendering) &:key— List rendering directive.- Custom Directives (
v-*) — Creating custom directive handlers. - Event, Key & Form Modifiers — Directive modifiers.
v-if/v-show— Conditional directives.v-model— Two-way binding directive.
7. Key Takeaways
- Directives are special template attributes prefixed with
v-. - They instruct Vue's template compiler to apply reactive behaviors directly to DOM elements.
- Core shorthands include
:forv-bind,@forv-on, and#forv-slot. - Directives take arguments (after
:), modifiers (after.), and expressions (inside=""). - Mustaches cannot be used in HTML attributes; directives must be used instead.