Vue.js course Β· Module 14: Directives & Plugins
Custom Directives - Basics
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 boundbeforeMount- before the element is inserted into the DOMmounted- the element is already in the DOM (most commonly used)beforeUpdate- before the parent component is updatedupdated- after the parent component is updatedbeforeUnmount- before removal from the DOMunmounted- 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. What are Custom Directives used for in Vue?
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.