Override the Code Block Element in Marksy

Here's how you can change the default rendering of code blocks using marksy.

An MDX Alternative

MDX is a popular superset of Markdown that allows rendering custom components from within the usual markdown formatting. Marksy is a competing library. It does the same thing, and at least in my experience was even easier to set up.

Compilation Configuration

Markdown must be compiled from its original format in order to be rendered as HTML.

My compilation function looks like this:

import marksy from "marksy"
import { createElement } from "react"
import { renderToStaticMarkup } from "react-dom/server"

function compileMarkdown(markdown) {
  const compile = marksy({
    createElement, 
    highlight,     // implemented elsewhere
    elements,      // implemented elsewhere
  })
  const result = compile(markdown, {})
  result.string = renderToStaticMarkup(result.tree)
  return result
}

Marksy allows setting your own createElement function. In my case, this is being provided by React. Final markup is also done by React.

Customizing Highlighting

Code highlight can come from anywhere. I chose to use the PrismJS library. It's used on the server, so I'm using the Node API. The highlight function is as follows:

import Prism from "prismjs"

const highlight = (language, code) => {
  return Prism.highlight(code, Prism.languages.javascript, language)
}

Customizing Elements

Marksy allows for overrides to how the markdown is represented in HTML. This is provided in the elements property given to marksy.

I wanted to change the code block of my markdown. (You know, those triple backtick blocks?) I wanted to set a tabIndex on the code element. I did that like this:

import { createElement } from "react"

const elements = {
  code({ language, code }) {
    return createElement(
      "pre",
      {},
      createElement("code", {
        dangerouslySetInnerHTML: { __html: highlight(language, code) },
        tabIndex: 0
      })
    )
  }
}

Note that I'm using React but not using JSX here. But if your environment constraints are different, you likely would use it. Because of the way marksy is composed, I also have to call my highlight method from within the code function.

Hook this set of functions into your markdown compilation pipeline, and you're set.

Do you have any suggestions for improvements on this method of overriding the code blocks in marksy?