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!