Pandoc syntax highlighting with Hakyll

Posted on March 2, 2023

As I’m setting up my new site with Hakyll, I’m looking to add a few features to what it offers out of the box, and the first one is syntax highlighting. Syntax highlighting is enabled by default with recent (>= 1.9) Pandocs, as per the Hakyll FAQ, but only in the sense that the generated HTML of fenced code blocks is decorated with class attributes that describe what kind of tokens they are (keywords, variable names, literal values, etc.)—you still need to “bring your own CSS”. So the question is: which CSS?

The most straightforward thing to do is to grab the colors from one of Pandoc’s built-in themes.1 You can list the available colorschemes with pandoc --list-highlight-styles, and get the info for a specific one of them with e.g. pandoc --print-highlight-style=espresso, but the info gets printed as JSON, not CSS, so it’ll need a little more massaging to get it web-ready.

There’s a great StackOverflow answer about how to generate the syntax highlighting CSS for a given Pandoc colorscheme—here are the steps in short:

  • Make a helper template file highlighting-css.template which contains the text $highlighting-css$.

  • Make a helper input file sample.md which contains a highlightable code block (in whatever programming language you like, but it does have to be tagged with some language, so that Pandoc knows to highlight it), for example:

    ``` haskell
    main = putStrLn "Hello world!"
    ```
  • Run Pandoc on that input file with the helper template, specifying the colorscheme to use for highlighting: for example, if you wanted the CSS for the espresso colorscheme, you would run pandoc --template=highlighting-css.template --highlight-style=espresso sample.md -o highlighting.css.

  • Now the file highlighting.css has your generated CSS.

You can stick the CSS file wherever you want; I have mine at css/syntax.css (along with css/default.css, where the main CSS for my site lives), and this rule in my site.hs:

match "css/*" $ do
  route   idRoute
  compile compressCssCompiler

But Pandoc only comes with a few themes, and only some of those are for light mode: the light mode ones are pygments, tango, kate, monochrome (which, as the name implies, doesn’t apply any colors), and haddock (which, fascinatingly, looks nothing like the highlighting I’m used to seeing in Haddock documentation). That JSON output we got from --print-highlight-style is somewhat standardized, though: the format is shared with KDE’s colorscheme specification, which means that we can also use any of the themes from the Kate Editor.

To do this, download one of KDE’s syntax highlighting theme files, and use the theme file as the argument to --highlight-style when running Pandoc to generate your highlighting.css. Unfortunately, not all of them work out of the box; I’m guessing it wouldn’t be too hard to figure out why and fix it, but after some experimentation with the ones that did “just work” without any extra finagling, I decided I liked the Breeze Light theme enough to go with that one, at least as a starting point. Here’s the shell command I ended up with:

pandoc --template=highlighting-css.template \
    --highlight-style=breeze-light.theme \
    sample.md -o css/syntax.css

Finally, if you’re interested in making your own theme from scratch, or just reading more, there’s a GitHub repo with a boilerplate theme file and more details about how Pandoc uses KDE’s theme format.


  1. Actually, the most straightforward thing to do is probably to just find another Hakyll site online that already has syntax highlighting with colors you like, and grab their CSS, but I’m guessing that if you wanted to do that, you would have done it already and you wouldn’t be reading a blog post about how to DIY it.↩︎