Syntax Highlighting
This page explains how to enable syntax highlighting for source blocks in Asciidoctor.js.
Default behavior
Without a syntax highlighter configured, Asciidoctor.js renders a source block like this:
[source,java]
....
public class Kalle {
public Kalle(final String pelle) {}
}
....
as plain HTML with language metadata on the <code> element:
<div class="content">
<pre class="highlight">
<code class="language-java" data-lang="java">public class Kalle {
public Kalle(final String pelle) {}
}</code>
</pre>
</div>
The class and data-lang attributes are present, but there is no highlighted markup.
To get visual syntax highlighting you need either a client-side library that runs in the browser, or a server-side highlighter that processes the source at conversion time.
Client-side highlighting with highlight.js
Asciidoctor.js ships with a built-in highlight.js adapter. When enabled, Asciidoctor.js injects the highlight.js stylesheet and script into the output document, and the browser applies highlighting when the page loads.
Standalone documents
To use the built-in adapter, convert with standalone: true and set the source-highlighter attribute to highlightjs (or highlight.js):
import { convert } from '@asciidoctor/core'
const content = `= Sample Java
[source,java]
....
public class Kalle {
public Kalle(final String pelle) {}
}
....`
const html = await convert(content, {
standalone: true, (1)
attributes: { 'source-highlighter': 'highlightjs' }, (2)
})
| 1 | The standalone option wraps the body in a full HTML document (<html>, <head>, <body>).
The highlight.js <link> and <script> tags are injected via the docinfo mechanism, which only runs in standalone mode. |
| 2 | Tells Asciidoctor.js to use the built-in highlight.js adapter. |
The generated document loads highlight.js from a CDN and calls hljs.highlightBlock() on every pre.highlight > code[data-lang] element.
|
If you set |
Customizing the theme
Override the default github theme by setting the highlightjs-theme attribute:
await convert(content, {
standalone: true,
attributes: {
'source-highlighter': 'highlightjs',
'highlightjs-theme': 'monokai',
},
})
Any theme name from the highlight.js theme gallery is accepted.
Self-hosted highlight.js
To serve highlight.js from your own host instead of the CDN, set the highlightjsdir attribute to the base URL of your installation:
await convert(content, {
standalone: true,
attributes: {
'source-highlighter': 'highlightjs',
'highlightjsdir': '/assets/highlight.js',
},
})
Asciidoctor.js will load styles/github.min.css and highlight.min.js relative to that URL.
Embedding in an existing page
If you are inserting the converted fragment into an existing HTML page (i.e. without standalone: true), you must include highlight.js yourself and initialize it after inserting the fragment:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.3/styles/github.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.3/highlight.min.js"></script>
import { convert } from '@asciidoctor/core'
const html = await convert(content) // standalone is false by default
document.getElementById('content').innerHTML = html
// Highlight all source blocks that Asciidoctor.js produced
document.querySelectorAll('pre.highlight > code[data-lang]').forEach((el) => {
hljs.highlightBlock(el)
})
Server-side (conversion-time) highlighting
Server-side highlighting processes the source at conversion time so the highlighted markup is embedded directly in the output HTML. This approach does not require any client-side JavaScript.
Asciidoctor.js does not ship a built-in server-side highlighter, but you can implement one by extending SyntaxHighlighterBase and overriding handlesHighlighting() → true and highlight().
Here is a minimal example using the highlight.js npm package to highlight at conversion time:
import { load, SyntaxHighlighterBase } from '@asciidoctor/core'
import hljs from 'highlight.js' // npm install highlight.js
class HljsServerHighlighter extends SyntaxHighlighterBase {
handlesHighlighting() {
return true (1)
}
highlight(node, source, lang, opts) {
if (lang && hljs.getLanguage(lang)) {
return hljs.highlight(source, { language: lang }).value (2)
}
return hljs.highlightAuto(source).value
}
}
const doc = await load(content, {
safe: 'safe',
syntax_highlighters: { 'hljs-server': HljsServerHighlighter }, (3)
attributes: { 'source-highlighter': 'hljs-server' },
})
const html = await doc.convert()
| 1 | Returning true tells Asciidoctor.js that this highlighter processes source at conversion time. |
| 2 | source is the raw source text; return the highlighted markup as a plain string. |
| 3 | Register the highlighter under the name used in source-highlighter. |
See Custom Syntax Highlighter for the full API.