Adding Code Blocks with Syntax Highlighting to WebFlow

EDIT: WebFlow now supports Code Blocks out of the box! However, it only supports them in Pages, not in CMS Collection Entries, so it’s not a total solution. This article’s approach works in CMS Collection Entries, so if you need code blocks there, read on!

I’m in the process of developing the marketing website for Arachnio. Being an API product, I need to embed code in some of the site’s pages and blog posts. The website is built on WebFlow, which I have found to be generally outstanding, but it does not support inline code or code blocks out of the box. Here’s how I got code blocks with syntax highlighting working in WebFlow.

Syntax Highlighting in Action!

When I discovered that WebFlow (sadly) does not support code blocks natively, Google quickly led me to this article about the problem, which outlines the following (excellent) approach: use a simple, tag-like syntax to decorate code blocks when you write the copy, and then use highlight.js and jQuery to do syntax highlighting on page load. Simple, direct, elegant.

However, while the article’s design is good, its implementation got several important details wrong. After some troubleshooting, I ended up with the following solution.

Code to Add in Header Section

First, I added the following imports to the head of the page. Functionally, it boils down to: add highlight.js itself; add any language plugins that are needed, e.g., json; and add a stylesheet to apply the styling.

<!-- Add highlight.js -->
<script
    defer
    src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.9/highlight.min.js">
</script>

<!-- Add highlight.js language highlighters -->
<script
    defer
    src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.9/languages/json.min.js">
</script>

<!-- Add code highlighting styles -->
<link
    rel="stylesheet"
    href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.9/styles/atom-one-dark.min.css"
/>

I made the following tweaks to the original code to get it working:

  • Change language highlighter tags from stylesheet imports to JavaScript imports, since that’s what they are
  • Make the script tags defer to minimize impact on page load time, since the page will load just fine without syntax highlighting

If your site has a light theme, then //cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.9/styles/atom-one-light.min.css would be a fine alternative stylesheet. There are also many, many others.

Code to Add in Footer Section

Next, I added the following highlight logic to the footer of the page. Essentially, the logic: finds the language markup “tags”; replaces the fake “tags” with real HTML tags; and then performs syntax highlighting using highlight.js.

<script>
/* Run when the page has loaded*/
$(document).ready(function(event) {
  /* This formats all the inline code examples. */
  $('p:contains("code-line"), li:contains("code-line")').each(function(index, el) {
    $(el).html(el.innerText.replace(
      /\{\%[\s\u00A0]*code-line[\s\u00A0]*\%\}(.*?)\{\%[\s\u00A0]*end-code-line[\s\u00A0]*\%\}/gi,
      '<code class="inline-code">$1</code>'
    ))
  })

  /* This formats all the code block examples. */
  $('p:contains("code-block"), li:contains("code-block")').each(function(index, el) {
    $(el).html(el.innerHTML.replace(
/\{\%(?:[\s\u00A0]|&nbsp;)*code-block(?:[\s\u00A0]|&nbsp;)*language=["']([^"']+)["'](?:[\s\u00A0]|&nbsp;)*\%\}(.*?)\{\%(?:[\s\u00A0]|&nbsp;)*end-code-block(?:[\s\u00A0]|&nbsp;)*\%\}/gims,
      "<pre><code class=\"$1\">$2</code></pre>"
    ))
  })

  /* Run Highlight JS on every code block */
  $('pre > code').each(function(index, codeBlock) {
    /* Remove first child <br> */
    codeBlock.removeChild(codeBlock.childNodes[0])
    hljs.highlightBlock(codeBlock)
  })
});
</script>

I made the following tweaks to the original code to get everything working:

  • Rename the tags (purely cosmetic)
  • Update whitespace regex expression. Replace instances of \s*, with (?:[\s\u00A0]|&nbsp;)*, which is a non-capturing group that matches not only conventional whitespace but also non-breaking spaces
  • Add the s flag to the multiline regular expression to activate dotall mode
  • Add the m flag to the multiline regular expression to active multiline mode

Adding to WebFlow

Now that we know the code to add, it’s time to add it! There are a couple of good candidate targets for this code in WebFlow:

  1. In “Head Code” and “Footer Code” in site settings. This will enable syntax highlighting on all pages, but also adds the overhead to all pages, whether they need it or not. This approach has the virtue of working on all sites.
  2. In “Head Code” and “Footer Code” on specific page type(s). Note that your template and/or site plan will determine if your individual page types have these fields, and indeed if you have some page types in your site at all (i.e., CMS plan).

In my case, I went with Option (2), since I only have code blocks on blog posts, at least for now. Also, I imported language highlighters for xml, json, Java, Python, and shell. You can always check the highlight.js demo to see what language highlighters are available.

Header Code
Footer Code

Code Block Syntax

With these additions made, you can use the following syntax to add a new code block in WebFlow:

{% code-block language="shell" %}
/* ARACHNIO_BASE_URL and BLOBR_API_KEY are from Step 1 */
ArachnioClient client=new DefaultArachnioClient(ARACHNIO_BASE_URL, BLOBR_API_KEY);

/* We chose the link in Step 2 */
ExtractedLink response = client.extractLink(
  "https://www.nytimes.com/2022/08/25/science/spiders-misinformation-rumors.html");

/* And here is our response! */
if(response.getEntity() instanceof ArticleWebpageEntityMetadata article) {
   /* Coffee Drinking Linked to Lower Mortality Risk, New Study Finds */
   System.out.println(article.getTitle());
}
{% end-code-block %}

The Results

The resulting code blocks render beautifully on the site.

Example Java Syntax Highlighting

Check out this article about scraping news articles with Arachnio using Java to see the syntax highlighting live in action!

Known Issues

For reasons I have not yet run to ground, line comments (e.g., // in Java or # in Python) break syntax highlighting. For now, just use block comments or similar (e.g., /* */ in Java or """ doc """ in Python).