Vue Directives

Special attributes that apply reactive behavior to DOM

⚡ What are Vue Directives?

Directives are special attributes with the v- prefix that apply reactive behavior to the DOM. They tell Vue to do something with a DOM element, like show/hide, loop through data, or bind values dynamically.


<!-- v-if directive conditionally renders -->
<p v-if="isVisible">I am visible!</p>
                                    

Common Directives

👁️

v-if / v-show

Conditional rendering

<p v-if="show">Visible</p>
🔁

v-for

Render lists

<li v-for="item in items">
  {{ item }}
</li>
🔗

v-bind

Bind attributes dynamically

<img :src="imageUrl">
🖱️

v-on

Listen to events

<button @click="handleClick">
  Click
</button>

🔹 v-if, v-else-if, v-else

Conditionally render elements based on conditions:

<template>
  <div>
    <p v-if="score >= 90">Excellent!</p>
    <p v-else-if="score >= 70">Good job!</p>
    <p v-else-if="score >= 50">Keep trying!</p>
    <p v-else>Need improvement</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const score = ref(85)
</script>

Output (score = 85):

Good job!

🔹 v-show

Toggle element visibility with CSS display property:

<template>
  <button @click="isVisible = !isVisible">Toggle</button>
  <p v-show="isVisible">Now you see me!</p>
</template>

<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>

v-if vs v-show: v-if removes element from DOM, v-show just hides it with CSS. Use v-show for frequent toggles.

🔹 v-for

Render lists by iterating over arrays or objects:

<template>
  <ul>
    <li v-for="(fruit, index) in fruits" :key="index">
      {{ index + 1 }}. {{ fruit }}
    </li>
  </ul>
</template>

<script setup>
import { ref } from 'vue'
const fruits = ref(['Apple', 'Banana', 'Orange'])
</script>

Output:

  • 1. Apple
  • 2. Banana
  • 3. Orange

🔹 v-bind (or :)

Dynamically bind attributes to expressions:

<template>
  <img :src="imageUrl" :alt="imageAlt">
  <a :href="link">Visit Site</a>
  <div :class="{ active: isActive }">Content</div>
  <button :disabled="isDisabled">Submit</button>
</template>

<script setup>
import { ref } from 'vue'
const imageUrl = ref('/logo.png')
const imageAlt = ref('Logo')
const link = ref('https://vuejs.org')
const isActive = ref(true)
const isDisabled = ref(false)
</script>

Shorthand: :src is shorthand for v-bind:src

🔹 v-on (or @)

Listen to DOM events and execute JavaScript:

<template>
  <button @click="count++">Clicked {{ count }} times</button>
  <input @input="handleInput" placeholder="Type here">
  <form @submit.prevent="handleSubmit">
    <button type="submit">Submit</button>
  </form>
</template>

<script setup>
import { ref } from 'vue'
const count = ref(0)

const handleInput = (e) => {
  console.log(e.target.value)
}

const handleSubmit = () => {
  console.log('Form submitted')
}
</script>

Event Modifiers: .prevent, .stop, .once, .enter, etc.

🔹 v-model

Create two-way data binding on form inputs:

<template>
  <input v-model="message" placeholder="Type something">
  <p>Message: {{ message }}</p>
  
  <input type="checkbox" v-model="checked">
  <p>Checked: {{ checked }}</p>
</template>

<script setup>
import { ref } from 'vue'
const message = ref('')
const checked = ref(false)
</script>

Result:

Input value automatically syncs with data

🔹 v-text and v-html

Update element's text or HTML content:

<template>
  <!-- v-text (same as {{ }} but overwrites content) -->
  <p v-text="message"></p>
  
  <!-- v-html (renders HTML, use with caution) -->
  <div v-html="htmlContent"></div>
</template>

<script setup>
import { ref } from 'vue'
const message = ref('Hello Vue!')
const htmlContent = ref('<strong>Bold text</strong>')
</script>

Warning: Never use v-html with user-provided content (XSS risk).

🔹 Custom Directives

Create your own directives for reusable DOM manipulation:

// Define custom directive
const vFocus = {
  mounted: (el) => el.focus()
}

// Use in template
<input v-focus />

🧠 Test Your Knowledge

Which directive creates two-way data binding?