Writing Custom Vue.js Directives

Published on March 30, 2017

Joshua Bemenderfer

Writing Custom Vue.js Directives

When you talk about Vue.js, you usually talk about Components. Components, components, components. Components aren’t the only thing you can write with Vue though, and it’s a good thing too. What if you want to apply modifiers to your components? That’s where directives come in. Whether you knew it or not, you’ve been using them already. v-if, v-model, and v-for are all examples of directives. Today, we’re going to show you how to add an important directive that performs a critical task that we can’t live without. Setting the background of its element to a nice baby blue.

Creating a Directive

Let’s get right on into the thick of it then. Create a new file called AnnoyingBackgroundDirective.js.

Now, let’s write the directive. A directive is just an object with a few special functions on it.

import Vue from 'vue';

const defaultBackgroundColor = '#86bbff'

// Initialize the annoying-background directive.
export const AnnoyingBackground = {
  bind(el, binding, vnode) {
    // Allow users to customise the color by passing an expression.
    const color = binding.expression || defaultBackgroundColor

    // el might not be present for server-side rendering.
    if (el) {
      // Set the element's background color.
      el.style.backgroundColor = color

// You can also make it available globally.
Vue.directive('annoying-background', AnnoyingBackground)

Now to use it in a component, simply add it to your component template prefixed with a v-.

    <p v-annoying-background>Baby blue looks good on me.</p>
    <p v-annoying-background="#0f0">I prefer neon green.</p>

import { AnnoyingBackground } from './AnnoyingBackgroundDirective.js';

export default {
  directives: {

More Details

A directive has five possible hooks:

  • bind(element, binding, vnode) - Called when the directive is first bound to the component or element.
  • inserted(element, binding, vnode) - Called when the component or element is inserted into it’s parent node. It may not be in the DOM yet.
  • update(element, binding, vnode, oldVnode) - Called when the containing component has updated but potentially before its children do.
  • componentUpdated(element, binding, vnode, oldVnode) - Called when the containing component has updated but after its children do.
  • unbind(element, binding, vnode) - Called when the directive is unbound from the component or element.

The arguments are these:

  • element - The element the directive is bound to. May be undefined.
  • binding - (This is the fun one.) Contains any arguments, values, and modifiers passed to the directive.
    • binding.name - The name of the directive.
    • binding.value - The value of a JS expression passed to the directive, if any. (ie. v-directive="{cake: 'chocolate'}" -> binding.value.cake === 'chocolate')
    • binding.oldValue - The previous value of the directive, only provided in update and componentUpdated.
    • binding.expression - The value expression as a string: v-directive="{cake: 'chocolate'}" -> binding.expression === '{cake: 'chocolate'}'
    • binding.arg - The argument passed to the directive, if any. v-directive:myArg -> binding.arg === 'myArg'
    • binding.modifiers - An object containing any modifiers passed to the directive as booleans. v-directive.modifier.modifier2 -> JSON.stringify(binding.modifiers) === {"modifier": true, "modifier2": true}
  • vnode - This is a virtual node used by Vue’s renderer. Don’t touch this unless you know what you’re doing. :P
  • oldVnode - The previous version of the above vnode. Only available in the update hooks.

So yeah, directives are really simple to create, but you can do a lot of crazy stuff with them if you so wish. Here’s the documentation.

Bonus Round

  • Try creating a conditional directive! Hint: You’ll probably need to hook into the vNode API. Sorry.

[itemprop=articleSection] ul ul li::before { content: “”; left: 36px; margin-top: 9px; position: absolute; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-left: 4px solid #EFBB35; border-top: 4px solid #EFBB35; border-bottom: 4px solid #EFBB35; border-right: 4px solid #EFBB35; } [itemprop=articleSection] ul ul li, [itemprop=articleSection] ul ul li code { font-size: 1rem; } <style> </div>

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Joshua Bemenderfer


While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel