Vue components vs directives

Vue components vs directives

This article is more than four years old. The content may be outdated, especially technical examples or references to tooling.

Vue components and custom directives both help you reuse code, but they solve different problems. A component defines a piece of your interface, including its template and behaviour. A directive adds behaviour to an existing element when you need direct access to the DOM.

You probably already use built-in directives such as v-if, v-for and v-model. You can also write your own. Here is how to decide when a custom directive is useful and when a component is the better choice.

The differences between components and directives

Characteristics of a component

A component packages a reusable part of the interface. It can have a template, local state, props and events. For example, this counter component owns both the button's appearance and its behaviour:

Vue.component('button-counter', {
  data: () => ({
    count: 0
  }),
  template: '<button @click="count++">You clicked me {{ count }} times.</button>'
});

The data function returns a new object for each component instance. The parentheses around ({ count: 0 }) make the arrow function return that object. Without them, the braces would form a function body with no return value.

Use the component in a Vue template with <button-counter></button-counter>. Vue renders the button and updates its text as the count changes. Place two instances on a page and each keeps its own counter.

Components also have their own lifecycle hooks. See the component guide and lifecycle diagram for more detail.

Characteristics of a directive

A custom directive attaches behaviour to an element through an attribute with the v- prefix. It does not define a component template or create its own component instance. A small example is moving focus to an input:

Vue.directive('focus', {
  inserted: el => {
    el.focus();
  }
});

Apply it to a focusable element in your template:

<input type="text" v-focus>

The inserted hook runs when the element is inserted into its parent. This can also happen later, when an element is added dynamically; it is not a page-load event. The parent does not necessarily have to be attached to the document yet.

Unlike a component, a directive has hooks tied to its bound element. The directive documentation describes these five hooks:

  • bind: runs once when the directive is first bound to the element.
  • inserted: runs when the element is inserted into its parent node.
  • update: runs after the containing component's virtual node updates, possibly before its children update. The directive's value may be unchanged.
  • componentUpdated: runs after the containing component's virtual node and its children's virtual nodes have updated.
  • unbind: runs once when the directive is unbound. Use it to clean up listeners or other resources the directive created.

Should I use a component or a directive?

Start with what you want to reuse. For a button, form field or other interface element with its own markup and behaviour, a component is usually the right place. Props and events give it a clear interface to the rest of the application.

Choose a directive when the reusable behaviour needs direct DOM access and can be attached to an existing element. Focusing an input is a good example: the directive does not need to own the input's value, label or validation messages.

Before writing a directive, check whether a normal Vue binding already handles the job. A class binding or event handler is often enough. Validation rules and API requests do not automatically belong in a directive simply because they relate to an input.

The two approaches can work together. A form-field component can own the label, input and error message while using a focus directive on its input. The decision is about responsibility, not just whether the solution adds another HTML tag.

Conclusion

Use components to build reusable pieces of your interface. Use custom directives for focused behaviour that needs access to an existing DOM element. Keep each responsible for a clear task so the result stays easy to understand and reuse.

Comments

There are no comments yet, leave yours below.

Leave a comment

Do you have an addition, question or experience related to this article? Share it below.

Comments are briefly reviewed before they appear.

Read more about:

Vue components disappear in AEM

Vue components disappear in AEM

Editing a component in AEM can replace its HTML without restarting Vue, leaving the component invisible in the editor. This article walks through the integration problem and a custom refresh approach, including iframe handling, to keep Vue components working during authoring.

Continue reading

Communication between Vue components

How should Vue components share data without becoming tightly coupled? This article compares props and events, the Vue 2 .sync modifier and an event bus, alongside the pitfalls of reaching directly into parent or child instances. The aim is to make communication explicit while keeping components understandable and reusable.

Continue reading

Starten met unit testen in Vue

Frontendlogica in Vue kun je ook met unit tests controleren. Aan de hand van een klein component bouwen we een test op met Jasmine en Karma: het component laden, afzonderlijk gedrag herkennen en testgevallen kiezen. Daarbij kijken we naar verschillende invoerwaarden en grenzen, zodat de test meer doet dan alleen de code uitvoeren.

Lees verder