Vue.js course Β· Module 14: Directives & Plugins

Custom Directives - Basics

2 min read
In this lesson5

Welcome to the NOVA LAB Command Center! Year 2087 - the space station interfaces require precise control over DOM elements. Vue provides Custom Directives that allow you to directly manipulate elements at a lower level than templates.

What Are Custom Directives?

Vue has built-in directives: v-if, v-for, v-model, v-show. But you can also create your own! Custom Directives provide direct access to the DOM element - something you can't achieve with templates alone.

Directives are an excellent tool when you need:

  • automatic focus on an input
  • handling clicks outside an element
  • lazy-loading images
  • custom tooltips

Global Registration: app.directive()

1const app = createApp(App)
2
3app.directive('focus', {
4  mounted(el) {
5    el.focus()
6  }
7})

Now you can use v-focus in any component:

1<template>
2  <input v-focus placeholder="Auto-focus!" />
3</template>

Local Registration

In a component, you can register a directive locally:

1<script setup>
2const vHighlight = {
3  mounted(el) {
4    el.style.backgroundColor = '#00ff88'
5    el.style.padding = '4px 8px'
6    el.style.borderRadius = '4px'
7  }
8}
9</script>
10
11<template>
12  <span v-highlight>Important text</span>
13</template>

Important convention: In <script setup>, a local directive must have a name starting with v (e.g., vHighlight), and in the template you use it as v-highlight (camelCase converted to kebab-case).

Directive Lifecycle Hooks

Directives have hooks similar to the component lifecycle:

  • created - before the element's attributes are bound
  • beforeMount - before the element is inserted into the DOM
  • mounted - the element is already in the DOM (most commonly used)
  • beforeUpdate - before the parent component is updated
  • updated - after the parent component is updated
  • beforeUnmount - before removal from the DOM
  • unmounted - element removed from the DOM
1app.directive('log', {
2  mounted(el) {
3    console.log('Element added to DOM:', el.tagName)
4  },
5  updated(el) {
6    console.log('Element updated:', el.tagName)
7  },
8  unmounted(el) {
9    console.log('Element removed:', el.tagName)
10  }
11})

Shorthand Directive Form

If you only need mounted and updated with the same logic, you can use the shorthand form - a function instead of an object:

1app.directive('color', (el, binding) => {
2  el.style.color = binding.value
3})

This is equivalent to:

1app.directive('color', {
2  mounted(el, binding) {
3    el.style.color = binding.value
4  },
5  updated(el, binding) {
6    el.style.color = binding.value
7  }
8})
Code for this lesson: App.vue
1<script setup>
2import { ref } from 'vue'
3
4// Local v-focus directive
5const vFocus = {
6  mounted(el) {
7    el.focus()
8  }
9}
10
11// Local v-highlight directive
12const vHighlight = {
13  mounted(el, binding) {
14    el.style.backgroundColor = binding.value || 'rgba(0, 255, 136, 0.15)'
15    el.style.padding = '4px 8px'
16    el.style.borderRadius = '4px'
17  },
18  updated(el, binding) {
19    el.style.backgroundColor = binding.value || 'rgba(0, 255, 136, 0.15)'
20  }
21}
22
23// Local v-color directive (shortened form)
24const vColor = (el, binding) => {
25  el.style.color = binding.value || '#00ff88'
26}
27
28const searchQuery = ref('')
29const showPanel = ref(true)
30</script>
31
32<template>
33  <div class="nova-lab">
34    <h1>Custom Directives - Podstawy</h1>
35
36    <section class="section">
37      <h2>v-focus - Auto Focus</h2>
38      <input
39        v-focus
40        v-model="searchQuery"
41        placeholder="Enter station command..."
42        class="input"
43      />
44      <p class="hint">This input gets focus automatically</p>
45    </section>
46
47    <section class="section">
48      <h2>v-highlight - Highlighting</h2>
49      <p v-highlight>Default highlight (green)</p>
50      <p v-highlight="'rgba(0, 180, 216, 0.2)'">Cyan highlight</p>
51      <p v-highlight="'rgba(231, 76, 60, 0.2)'">Red highlight</p>
52    </section>
53
54    <section class="section">
55      <h2>v-color - Shortened form</h2>
56      <p v-color="'#00ff88'">Green text</p>
57      <p v-color="'#00b4d8'">Cyan text</p>
58      <p v-color="'#e74c3c'">Red text</p>
59    </section>
60  </div>
61</template>
62
63<style scoped>
64.nova-lab {
65  background: #0a0e27;
66  color: #c0c0c0;
67  min-height: 100vh;
68  padding: 20px;
69  font-family: monospace;
70}
71h1 { color: #00ff88; margin-bottom: 20px; }
72h2 { color: #00b4d8; font-size: 16px; margin-bottom: 10px; }
73
74.section {
75  background: rgba(0, 180, 216, 0.05);
76  border: 1px solid rgba(0, 180, 216, 0.2);
77  padding: 15px;
78  border-radius: 8px;
79  margin-bottom: 15px;
80}
81
82.input {
83  background: rgba(0, 255, 136, 0.05);
84  border: 1px solid #00ff88;
85  color: #00ff88;
86  padding: 10px 16px;
87  border-radius: 6px;
88  font-family: monospace;
89  font-size: 14px;
90  width: 100%;
91  box-sizing: border-box;
92}
93.input:focus {
94  outline: none;
95  box-shadow: 0 0 8px rgba(0, 255, 136, 0.3);
96}
97.hint {
98  color: #666;
99  font-size: 12px;
100  margin-top: 6px;
101}
102</style>

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What are Custom Directives used for in Vue?

  2. 2. How do you register a directive globally in Vue?

These are 2 of 3 questions for this lesson. Solve the rest in the game.

Hands-on tasks in the game

  • Code editor

    Define a vFocus directive with a mounted hook and use it on an input.

  • Click in order

    Arrange the Custom Directive hooks in the order they are called:

  • Code editor

    Use the shorthand directive form (function instead of object) to set the text color.

Useful articles