My Markdown-It Configuration
An overview of the markdown-it and highlight.js configurations used on my website.
I use markdown-it and highlight.js to render my blog posts. Out of the box, markdown-it and highlight.js may provide all the functionality you need, however, customising them enables you to do stuff like:
- Display the language of code blocks
 - Add new language aliases for syntax highlighting
 - Use BEM class names
 - Add heading anchors
 - Use proper quote characters e.g. “double quotes”
 - Open external links in new tabs
 - Write abbreviations, subscript, superscript and more in Markdown
 
The Configuration
I’ve been slowly tinkering with my configuration and I’ll keep updating this blog post as I change it. In this short blog post I’ll explain everything in the configuration, but before I do that, here’s the whole thing:
const hljs = require("highlight.js");
hljs.configure({
  classPrefix: "highlight__",
});
hljs.registerLanguage("vue", () => hljs.getLanguage("html"));
 
const markdown = require("markdown-it")({
  html: true,
  xhtmlOut: true,
  breaks: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="highlight" data-language="${lang.toUpperCase()}"><code>${
          hljs.highlight(lang, str, true).value
        }</code></pre>`;
      } finally {
        // No syntax highlighting
      }
    }
 
    return `<pre class="highlight"><code>${markdown.utils.escapeHtml(
      str
    )}</code></pre>`;
  },
})
  .use(require("markdown-it-anchor"), {
    permalink: true,
    permalinkSymbol: "#",
    permalinkSpace: false,
  })
  .use(require("markdown-it-task-lists"), {
    label: true,
  })
  .use(require("markdown-it-abbr"))
  .use(require("markdown-it-sup"))
  .use(require("markdown-it-sub"))
  .use(require("markdown-it-mark"))
  .use(require("markdown-it-ins"));const hljs = require("highlight.js");
hljs.configure({
  classPrefix: "highlight__",
});
hljs.registerLanguage("vue", () => hljs.getLanguage("html"));
 
const markdown = require("markdown-it")({
  html: true,
  xhtmlOut: true,
  breaks: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="highlight" data-language="${lang.toUpperCase()}"><code>${
          hljs.highlight(lang, str, true).value
        }</code></pre>`;
      } finally {
        // No syntax highlighting
      }
    }
 
    return `<pre class="highlight"><code>${markdown.utils.escapeHtml(
      str
    )}</code></pre>`;
  },
})
  .use(require("markdown-it-anchor"), {
    permalink: true,
    permalinkSymbol: "#",
    permalinkSpace: false,
  })
  .use(require("markdown-it-task-lists"), {
    label: true,
  })
  .use(require("markdown-it-abbr"))
  .use(require("markdown-it-sup"))
  .use(require("markdown-it-sub"))
  .use(require("markdown-it-mark"))
  .use(require("markdown-it-ins"));Configuring Highlight.js
Firstly, I configure highlight.js. You can use the syntax highlighter of your choice in conjunction with markdown-it; the most popular syntax highlighting libraries are highlight.js and Prism, it’s up to you which you use. I do two things in setting up syntax highlighting:
- Change the 
classPrefixtohighlight__. All my other class names use BEM so I felt the need to do this for consistency’s sake. - Set up language aliases. I’ve only needed one alias, namely highlighting 
vuecode blocks ashtml. 
const hljs = require("highlight.js");
hljs.configure({
  classPrefix: "highlight__",
});
hljs.registerLanguage("vue", () => hljs.getLanguage("html"));const hljs = require("highlight.js");
hljs.configure({
  classPrefix: "highlight__",
});
hljs.registerLanguage("vue", () => hljs.getLanguage("html"));Configuring Markdown-It
Secondly, I pass some configuration options to markdown-it:
html: trueallows me to put raw HTML into my Markdown files. This also allows me to put Vue components into my Markdown files, as explained in my previous blog post, Build a Blog with Nuxt and Markdown.xhtmlOut: trueconverts newlines\nin paragraphs into break tags<br/>.typographer: trueenables some “language-neutral replacement” and beautifies quotation marks.
const markdown = require("markdown-it")({
  html: true,
  xhtmlOut: true,
  breaks: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="highlight" data-language="${lang.toUpperCase()}"><code>${
          hljs.highlight(lang, str, true).value
        }</code></pre>`;
      } finally {
        // No syntax highlighting
      }
    }
 
    return `<pre class="highlight"><code>${markdown.utils.escapeHtml(
      str
    )}</code></pre>`;
  },
});const markdown = require("markdown-it")({
  html: true,
  xhtmlOut: true,
  breaks: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="highlight" data-language="${lang.toUpperCase()}"><code>${
          hljs.highlight(lang, str, true).value
        }</code></pre>`;
      } finally {
        // No syntax highlighting
      }
    }
 
    return `<pre class="highlight"><code>${markdown.utils.escapeHtml(
      str
    )}</code></pre>`;
  },
});Within the markdown-it configuration, I also enable syntax highlighting. Essentially, I attempt to highlight the code with the given language using highlight.js and if this fails then I just degrade to the plain text in a code block.
Note that within the syntax highlighting configuration, I add a data-language attribute which stores the language of the code block. This allows me to add the name of the language to the top right of the code block using a pseudo-element like so:
pre[data-language]::after {
  background-color: grey;
  content: "." attr(data-language); /* The cool bit! */
  padding: 0.5rem;
  position: absolute;
  right: 0;
  top: 0;
}pre[data-language]::after {
  background-color: grey;
  content: "." attr(data-language); /* The cool bit! */
  padding: 0.5rem;
  position: absolute;
  right: 0;
  top: 0;
}Markdown-It Plugins
There are some great plugins out there to extend the functionality of markdown-it. I use several plugins to:
- Add heading anchors
 - Add task lists to Markdown
 - Add abbreviations
 - Add superscript text
 - Add subscript text
 - Add marked text
 - Add inserted text
 
  .use(require('markdown-it-anchor'), {
    permalink: true,
    permalinkSymbol: '#',
    permalinkSpace: false
  })
  .use(require('markdown-it-task-lists'), {
    label: true
  })
  .use(require('markdown-it-abbr'))
  .use(require('markdown-it-sup'))
  .use(require('markdown-it-sub'))
  .use(require('markdown-it-mark'))
  .use(require('markdown-it-ins'))  .use(require('markdown-it-anchor'), {
    permalink: true,
    permalinkSymbol: '#',
    permalinkSpace: false
  })
  .use(require('markdown-it-task-lists'), {
    label: true
  })
  .use(require('markdown-it-abbr'))
  .use(require('markdown-it-sup'))
  .use(require('markdown-it-sub'))
  .use(require('markdown-it-mark'))
  .use(require('markdown-it-ins'))Have fun tinkering with your Markdown configuration!