Vue.js Syntax Highlighting with highlight.js

Everyone loves a good syntax highlighting. This post explains how to use highlight.js for syntax highlighting in a Vue.js application. The method shown here allows syntax highlighting both on original creation of an element as well as on updates to the source-code, using a simple v-highlightjs directive such as this:

<pre v-highlightjs><code class="javascript"></code></pre>

You can see a live example here: jsfiddle.net/metachris/1vz9oobc.

To achieve this, we just need to install the highlight.js dependency and create a custom highlightjs directive. Let’s dive straight in!

Note: The code from this post is now also published as npm package vue-highlightjs, which you can easily use in your project.


Install the highlight.js dependency

The first step is to install highlight.js as a dependency with the npm node package manager:

$ npm install --save highlight.js

Include the highlight.js CSS file in your HTML

To reference the highlight.js CSS style sheet from the HTML, just include a <link rel="stylesheet" tag which points to either a downloaded highlight.css file or to their CDN URL:

<!-- Downloaded and saved in /static/css/highlight.css -->
<link rel="stylesheet" href="/static/css/highlight.css">

<!-- Or if you want to use the stylesheet from the CDN -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/default.min.css">

highlight.js comes with a number of different styles, which are defined by using a specific stylesheet for each style (we are using the default style here). For other available styles look into the highlight.js styles directory (and don’t forget to add “.min” before “.css”).


A custom Vue.js directive: v-highlightjs

To use highlight.js from within Vue.js components, we are going to create a custom Vue.js directive called highlightjs. You can declare this directive directly in your main.js file:

import Vue from 'vue'
import hljs from 'highlight.js'

...

Vue.directive('highlightjs', {
  deep: true,
  bind: function (el, binding) {
    // on first bind, highlight all targets
    let targets = el.querySelectorAll('code')
    targets.forEach((target) => {
      // if a value is directly assigned to the directive, use this
      // instead of the element content.
      if (binding.value) {
        target.textContent = binding.value
      }
      hljs.highlightBlock(target)
    })
  },
  componentUpdated: function (el, binding) {
    // after an update, re-fill the content and then highlight
    let targets = el.querySelectorAll('code')
    targets.forEach((target) => {
      if (binding.value) {
        target.textContent = binding.value
        hljs.highlightBlock(target)
      }
    })
  }
})

(You can also use the npm package vue-highlightjs instead of declaring the directive manually.)


Using v-highlightjs

To highlight code (for example JavaScript) which is either hardcoded in a template or stored in a variable (or getter) called sourcecode, we can use the v-highlightjs directive like this:

<pre v-highlightjs><code class="javascript">{{ sourcecode }}</code></pre>

Reacting to code updates

highlight.js replaces the content of the <code> block. If using the directive as shown above, updating the source-code after the initial highlighting does not work anymore. To be able to update the code and highlight it again after an update, pass the variable directly into the v-highlightjs directive like this:

<pre v-highlightjs="sourcecode"><code class="javascript"></code></pre>

Live Example


References


You can reach out to me via @metachris. Please let me know if you have any feedback or suggestions!