📖 Scenario: You are building a Vue 3 app that needs to highlight text when the user hovers over it. Instead of repeating the same hover style everywhere, you want to create a reusable custom directive to handle this behavior.
🎯 Goal: Create a Vue 3 app that uses a custom directive called v-highlight to add a yellow background color on hover to any text element.
📋 What You'll Learn
Create a Vue 3 app using the Composition API with <script setup>
Define a custom directive named highlight
The directive should add a yellow background color when the mouse is over the element
The directive should remove the background color when the mouse leaves
Use the directive on a paragraph element in the template
💡 Why This Matters
🌍 Real World
Custom directives let you add reusable behaviors to HTML elements in Vue apps, like tooltips, animations, or input masks.
💼 Career
Understanding custom directives is useful for frontend developers working with Vue to create clean, maintainable, and reusable UI behaviors.
Progress0 / 4 steps
1
Set up the Vue 3 app skeleton
Create a Vue 3 component with <template> and <script setup> tags. Inside the template, add a paragraph with the text Hover over me!.
Vue
Hint
Start by writing the basic Vue 3 component structure with a paragraph inside the template.
2
Create the custom directive variable
Inside the <script setup> tag, create a constant called highlight that is an object with two functions: mounted and unmounted. For now, leave the functions empty.
Vue
Hint
Define the highlight object with mounted and unmounted lifecycle hooks for the directive.
3
Add hover event listeners in the directive
Inside the mounted function of highlight, add event listeners to el for mouseenter and mouseleave. On mouseenter, set el.style.backgroundColor to yellow. On mouseleave, reset el.style.backgroundColor to an empty string. Inside unmounted, remove these event listeners.
Vue
Hint
Use el.addEventListener to add hover handlers and store them on el so you can remove them later.
4
Register and use the custom directive in the template
Register the highlight directive in the component by adding v-highlight to the paragraph element in the template. Also, add directives={{ highlight }} to the <script setup> block using defineExpose or by exporting the directive properly.
Vue
Hint
Add v-highlight to the paragraph and expose the directive using defineExpose with directives: { highlight }.
Practice
(1/5)
1. Why are custom directives useful in Vue?
easy
A. They add reusable behaviors directly to HTML elements.
B. They replace Vue components entirely.
C. They automatically fetch data from APIs.
D. They style elements with CSS only.
Solution
Step 1: Understand the purpose of custom directives
Custom directives let you add special behaviors to HTML elements that you can reuse.
Step 2: Compare with other options
They do not replace components, fetch data, or only style elements; they control DOM behavior.
Final Answer:
They add reusable behaviors directly to HTML elements. -> Option A
Quick Check:
Custom directives = reusable element behaviors [OK]
Hint: Custom directives add behaviors to elements, not replace components [OK]
Common Mistakes:
Thinking directives replace components
Confusing directives with data fetching
Assuming directives only style elements
2. Which is the correct syntax to register a global custom directive named focus in Vue 3?
easy
A. app.component('focus', { mounted(el) { el.focus() } })
B. Vue.directive('focus', function(el) { el.focus() })
C. app.directive('focus', { mounted(el) { el.focus() } })
D. app.use('focus', { mounted(el) { el.focus() } })
Solution
Step 1: Recall Vue 3 global directive registration
In Vue 3, use app.directive(name, definition) to register directives globally.
Step 2: Check the options
app.directive('focus', { mounted(el) { el.focus() } }) uses app.directive with a proper object containing mounted hook. Others use wrong methods or syntax.
Final Answer:
app.directive('focus', { mounted(el) { el.focus() } }) -> Option C
Quick Check:
Vue 3 global directive = app.directive(name, definition) [OK]
Hint: Use app.directive() with hooks to register global directives [OK]
Common Mistakes:
Using Vue.directive instead of app.directive in Vue 3
Using app.use or app.component incorrectly
Passing a function instead of an object with hooks
A. The directive should use updated instead of mounted.
B. The removeEventListener call is missing the event handler function.
C. The mounted hook should not use arrow functions.
D. The unmounted hook should be named destroyed.
Solution
Step 1: Check event listener removal
removeEventListener requires the same event and handler function to remove the listener properly.
Step 2: Analyze the unmounted hook
Here, removeEventListener is called without the handler function, so the listener stays active causing memory leaks.
Final Answer:
The removeEventListener call is missing the event handler function. -> Option B
Quick Check:
removeEventListener needs event and handler [OK]
Hint: Always pass same handler to removeEventListener as added [OK]
Common Mistakes:
Omitting handler in removeEventListener
Confusing unmounted with destroyed hook
Thinking arrow functions cause errors here
5. You want to create a custom directive v-auto-focus that focuses an input only when it is visible on the page (not hidden by CSS). Which approach best uses custom directives to achieve this?
hard
A. In the mounted hook, check if el.offsetParent !== null before calling el.focus().
B. Use the updated hook to call el.focus() unconditionally every time.
C. Add a watcher on a data property to call el.focus() inside the directive.
D. Use a global event listener on window resize to focus the element.
Solution
Step 1: Understand visibility check in directives
Checking el.offsetParent !== null confirms the element is visible (not hidden by CSS).
Step 2: Apply focus conditionally in mounted hook
Focusing only when visible avoids errors and unwanted focus on hidden inputs.
Step 3: Evaluate other options
Updated hook focusing unconditionally may cause focus flicker; watchers and global listeners add complexity.
Final Answer:
In the mounted hook, check if el.offsetParent !== null before calling el.focus(). -> Option A
Quick Check:
Check visibility before focus in mounted hook [OK]
Hint: Check element visibility before focus in mounted hook [OK]
Common Mistakes:
Focusing without visibility check
Using updated hook causing repeated focus
Adding unnecessary watchers or global listeners
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.