How Markdown Here Implements Syntax Highlighting with Highlight.js

Markdown Here integrates Highlight.js by injecting the library into the extension's options page, then configuring the marked parser with a custom highlight callback that detects languages and returns colorized HTML wrapped in hljs CSS classes.

Markdown Here is a popular open-source browser extension that renders Markdown text into formatted HTML in email clients and web forms. One of its most valued features is syntax highlighting for fenced code blocks, which it achieves by leveraging the Highlight.js library. The implementation involves careful coordination between the extension's options storage, the Markdown parser configuration, and runtime theme management.

Loading the Highlight.js Library

The extension loads Highlight.js and its associated CSS themes through explicit script injection and configuration defaults, ensuring the library is available both for rendering previews and for the options page interface.

Script and Stylesheet Injection

In src/common/options.html, the Highlight.js library is loaded via a standard script tag:

<script src="highlightjs/highlight.js"></script>

Source: src/common/options.html (line 646)

This makes the hljs object available globally for the options page preview functionality.

Theme Management and Defaults

The default syntax highlighting theme is defined in src/common/options-store.js using the GitHub theme:

'syntax-css': {'__defaultFromFile__': '/common/highlightjs/styles/github.css', '__dataType__': 'text'}

Source: src/common/options-store.js (line 122)

To populate the theme selector in the options page, the extension reads a JSON catalogue of available themes:

Utils.getLocalFile(
  Utils.getLocalURL('/common/highlightjs/styles/styles.json'), 'json',
  function (syntaxStyles) { … });

Source: src/common/options.js (lines 71-78)

This allows users to switch between bundled themes like Monokai, Solarized, or GitHub without external dependencies.

Integrating Syntax Highlighting into the Markdown Parser

Markdown Here uses a custom build of marked, a JavaScript Markdown parser. The integration point is the highlight callback option, which intercepts code blocks during rendering and processes them through Highlight.js.

The Highlight Callback Function

In src/common/markdown-render.js, the marked parser is configured with a custom highlight function:

highlight: function (codeText, codeLanguage) {
  if (codeLanguage &&
      hljs.getLanguage(codeLanguage.toLowerCase())) {
    return hljs.highlight(codeText,
      { language: codeLanguage.toLowerCase(),
        ignoreIllegals: true }).value;
  }
  return codeText;
}

Source: src/common/markdown-render.js (lines 88-95)

This function performs three critical operations:

  1. Language Detection: Uses hljs.getLanguage() to verify that Highlight.js supports the specified language (case-insensitive).
  2. Syntax Highlighting: Calls hljs.highlight() with ignoreIllegals: true to gracefully handle unrecognized tokens without throwing errors.
  3. Fallback Handling: Returns the raw code text if no language is specified or recognized, ensuring the block still renders as plain text.

CSS Class Configuration

To ensure the highlighted output receives proper styling, the marked configuration sets a specific language prefix:

langPrefix: 'hljs language-',

Source: same file, line 86.

This prefix results in HTML output like <code class="hljs language-javascript">, which satisfies Highlight.js theme requirements—the hljs class triggers the theme's base styling, while the language-* class allows for language-specific overrides.

End-to-End Rendering Flow

Understanding the complete syntax highlighting pipeline helps clarify how the components interact:

  1. User Input: A fenced code block is written with a language specifier:

    ```javascript
    function greet(name) { console.log('Hi '+name); }
  2. Parser Invocation: Marked identifies the code block and extracts the language (javascript) and content.

  3. Highlight Processing: The custom highlight callback validates the language against hljs.getLanguage(), then calls hljs.highlight() to generate colorized HTML with ignoreIllegals: true.

  4. HTML Generation: Marked wraps the highlighted code in <pre><code class="hljs language-javascript">…</code></pre>.

  5. Styling Application: The extension injects the selected theme CSS (e.g., github.css) into the email compose window, applying colors to the hljs classes.

Practical Implementation Example

Below is a minimal, runnable example demonstrating the same Highlight.js integration pattern used by Markdown Here:

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="highlightjs/styles/github.css">
  <script src="highlightjs/highlight.js"></script>
</head>
<body>
  <pre><code id="code-block"></code></pre>

  <script>
    const sourceCode = `function calculateTotal(items) {
      return items.reduce((sum, item) => sum + item.price, 0);
    }`;

    // Check if language is supported
    if (hljs.getLanguage('javascript')) {
      // Apply syntax highlighting with error tolerance
      const highlighted = hljs.highlight(sourceCode, {
        language: 'javascript',
        ignoreIllegals: true
      }).value;
      
      document.getElementById('code-block').innerHTML = highlighted;
      document.getElementById('code-block').className = 'hljs language-javascript';
    }
  </script>
</body>
</html>

This example mirrors the production implementation in src/common/markdown-render.js, showing how to safely handle language detection and apply the hljs class for theme compatibility.

Summary

  • Library Loading: Highlight.js is injected via src/common/options.html and configured with default themes in src/common/options-store.js.
  • Parser Integration: The highlight callback in src/common/markdown-render.js bridges marked and Highlight.js, using hljs.getLanguage() for validation and hljs.highlight() for processing.
  • CSS Classes: The langPrefix: 'hljs language-' configuration ensures themes apply correctly to rendered code blocks.
  • Error Handling: The ignoreIllegals: true option prevents crashes when code contains tokens unexpected by the language definition.

Frequently Asked Questions

How does Markdown Here detect the programming language in a code block?

Markdown Here relies on the language specifier provided in the fenced code block (e.g., ```javascript). The highlight callback in src/common/markdown-render.js passes this string to hljs.getLanguage() to verify support before calling hljs.highlight(). If the language is unsupported or omitted, the code renders as plain text without highlighting.

Can I use a custom Highlight.js theme with Markdown Here?

Yes. While the extension defaults to github.css as defined in src/common/options-store.js, the options page loads a catalogue of bundled themes from src/common/highlightjs/styles/styles.json. Users can select alternatives like Monokai or Solarized through the UI, and the extension injects the corresponding CSS into the compose window.

What happens if Highlight.js doesn't recognize the language specified?

If hljs.getLanguage() returns falsy for the specified language, the highlight callback in src/common/markdown-render.js returns the raw code text unchanged. This ensures the code block still appears in the output, just without colorization, preventing rendering failures due to typos or unsupported language identifiers.

Is the syntax highlighting applied in real-time or during rendering?

Syntax highlighting is applied during the rendering phase when the user triggers the Markdown Here conversion (typically via a hotkey or button click). The markdown-render.js module processes the entire document at once, calling hljs.highlight() for each fenced code block before injecting the final HTML into the compose window.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →