0Pricing
Frontend Academy · Lesson

Custom Directives

Register global and local directives with lifecycle hooks like mounted and updated to encapsulate DOM manipulation logic outside components.

Custom Directives is a free Frontend Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Are Directives?

Directives are reusable DOM-manipulation logic attached to elements via the v- prefix. Built-in examples: v-if, v-for, v-model, v-show. Custom directives let you build your own.

Use Case: Auto-focus

A directive can encapsulate small bits of DOM manipulation that don't justify a wrapper component.

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

<script setup>
const vFocus = {
  mounted: (el) => el.focus()
};
</script>

Local Directive Registration

In <script setup>, declare directives with the v prefix — Vue auto-registers them locally.

<script setup>
const vColor = {
  mounted: (el, binding) => {
    el.style.color = binding.value;
  }
};
</script>

<template>
  <p v-color="'red'">Hello</p>
</template>

Global Directive Registration

Use app.directive(name, definition) to make a directive available everywhere.

// main.ts
const app = createApp(App);

app.directive('focus', {
  mounted: (el) => el.focus()
});

app.mount('#app');

Directive Lifecycle Hooks

Directives have hooks that mirror component lifecycle: created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted.

const vColor = {
  beforeMount(el, binding) {
    el.style.color = binding.value;
  },
  updated(el, binding) {
    el.style.color = binding.value;
  }
};

The binding Object

Hooks receive a binding object: value, oldValue, arg, modifiers, instance.

<p v-pin:bottom.left="200">Pinned</p>

// binding inside the directive:
// { value: 200, oldValue: ..., arg: 'bottom', modifiers: { left: true } }

Real Example: v-click-outside

A common directive — call a handler when the user clicks outside the element.

const vClickOutside = {
  mounted(el, binding) {
    el._handler = (e) => {
      if (!el.contains(e.target)) binding.value(e);
    };
    document.addEventListener('click', el._handler);
  },
  unmounted(el) {
    document.removeEventListener('click', el._handler);
  }
};

// Usage:
<div v-click-outside="closeMenu">...</div>

Real Example: v-tooltip

Attach a Tippy/Popper tooltip via a directive — keeps templates clean.

import tippy from 'tippy.js';

const vTooltip = {
  mounted(el, binding) {
    el._tippy = tippy(el, { content: binding.value });
  },
  updated(el, binding) {
    el._tippy?.setContent(binding.value);
  },
  unmounted(el) {
    el._tippy?.destroy();
  }
};

v-debounce: Throttle Input Events

Wire a debounce around an input's @input handler with a custom directive.

const vDebounce = {
  mounted(el, binding) {
    let timer;
    el.addEventListener('input', () => {
      clearTimeout(timer);
      timer = setTimeout(() => binding.value(el.value), 300);
    });
  }
};

<input v-debounce="search">

Directive vs Component vs Composable

Composables: stateful logic (data, refs). Components: reusable UI structure with their own template. Directives: pure DOM behaviour on an existing element. Choose directive when no template/markup is needed.

Performance Considerations

Directives run on every update. Keep them cheap. For expensive operations, gate on binding.value !== binding.oldValue to skip unnecessary work.

Quick Check

What is the difference between using a Vue directive vs a Vue component for adding behaviour?

Recap: Custom Directives

v-prefixed reusable DOM logic. Register locally (vName const in script setup) or globally (app.directive). Lifecycle hooks: mounted, updated, unmounted. binding gives value, oldValue, arg, modifiers. Use for pure DOM behaviour (focus, click-outside, tooltip, debounce). Components for markup; composables for stateful logic; directives for DOM augmentation.

Frequently asked questions

Is the “Custom Directives” lesson free?

Yes — the full text of “Custom Directives” is free to read here on the web, and the Frontend Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO.

What will I learn in “Custom Directives”?

Register global and local directives with lifecycle hooks like mounted and updated to encapsulate DOM manipulation logic outside components. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Frontend Academy?

No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Custom Directives” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Frontend Academy lesson?

Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. provide() and inject() for Dependency Injection
  2. Async Components and Suspense
  3. Custom Directives
  4. Plugin System: app.use()
← Back to Frontend Academy