Vue components vs directives

A directive is an HTML attribute with the purpose to reactively apply side effects to the DOM. In Vue directives are prefixed with v-, you probably have already used a few directives before; v-if, v-for, v-model etc. But did you know you can write your own directives? This article will explain the differences between Vue directives and Vue components and when you can add your own custom directives.

The differences between components and directives

Before we can make a conclusion about the usage we need a clear definition on what components and directives really are.

Characteristics of a component

Components are reusable Vue instances with a name. Components can be used as a custom element inside your Vue powered page

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

In this code example a new component “button-counter” is registered. You can use this component as a HTML-element: “”. Instead of seeing an empty element in your browser you will see the template of the component; a button with the text “You clicked me xx times”. So basically a component registers a custom HTML element, adds a template and adds some logic to it. Since a component has its own data/state you can use multiple instances of a component on one page.

Since each component implements a new Vue instance each component has its own Vue lifecycle with phases and hooks.

Characteristics of a directive

Directives are special attributes beginning with the v- prefix. In a Vue powered page it’s a special token in the markup that tells the library to do something to a DOM element.

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

In this example the directive v-focus will focus the element right after page load. Since it’s a Vue directive you can apply this directive on each HTML element and component like:

<input type="text" v-focus="">

So basically a directive is an HTML attribute which adds some logic to component and/or existing HTML elements.

Since a Vue directive is not a Component and therefore doesn't implement a new Vue instance you can't rely on the Vue lifecycle. However a Vue directive can listen and act on five different Vue hooks:

  • bind(element, binding, vnode) – Called when the directive is bound to the element.
  • componentUpdated(element, binding, oldVnode) – Called when the containing compontent has updated.
  • inserted(element, binding, vnode) – Called when the element is into it’s parents node.
  • update(element, binding, vnode, oldVnode) – Called when the containing component has updated.
  • unbind(element, binding, vnode) – Called when the directive is unbound from the element

Should I use a component or directive

If you ask yourself the question “should I use a component or directive?” the answer is almost always a component. There a few exceptions;

  • You want to choose a directive over a component when you're wanting to extend the functionality of HTML components and you suspect that you’re going to need this extendibility across multiple components, and you don't want your nest components as a result.
  • You want to choose a directive over a component when you want a single HTML tag to have multiple functionality. For example, an input element that validates the input and triggers an Ajax request. Assuming you could use the validation on multiple elements, it makes sense to split these up into two different things (a component for the request, and a directive for the validation). When you try to achieve this with components only you could make mixins or nest multiple components which make the result more complex and less SOLID.

Conclusion

Components are wrappers that are best suited when you need to insert (or add) your own HTML tags over something to render it. E.g. a widget or a custom button
Directives don't add tags but rather give you direct access to the HTML tag (to which you have added the directive). This gives you access to modify the attributes of that HTML element directly. E.g. set css styles, bind to an event, etc.