We’ll render a standard Markdown file to an HTML page that uses the Bulma CSS framework. We implement this program with a Golang Markdown package and a Golang template.
This article will show you how to render a Markdown file to an HTML page. This HTML page will use the Bulma CSS framework. To apply some of the special classes supplied by this CSS framework, we’ll need to write a special “hook” to adapt the way a few HTML tags are rendered. For this example, I’ll stick to adapting the rendering of the
img tags and adding
figure tags, but this can easily be expanded if needed.
To see the Markdown file that we’ll be using click here. The Markdown package for Golang that we’ll be using is this one. If you are not very familiar with Markdown or need a refresher, then this is a good resource.
You can find the complete code here.
Below, I’ll discuss the
renderHook() functions separately.
The main() function
In lines 3–22, you find the HTML header and footer for the HTML page we wish to render. These are pretty basic, except that we also import the Bulma CSS framework in line 9.
In lines 24–27, we read the markdown file using
ioutil.ReadFile() and we use
panic() to deal with any errors that may occur.
In lines 29–32, we determine the options we wish to send to the markdown renderer. Here, I found that
html.FlagsNone was the best flag to use. If you don’t put any flag, it will be set to
html.CommonFlags by default. In my experience, though, this may give unwanted results. Not rendering the bullet points would be one example.
The second thing to note here is that we set
RenderNodeHook to the
renderHook() function. This custom function takes care of rendering the
image nodes. More on that later.
In lines 33 and 34, we render the Markdown content to HTML. The markdown renderer seems to return a
byte slice. Therefore I use the
string() function to convert this into a string before feeding the
output to the template.
In lines 36–38, we create a simple Golang template that consists of the header, a variable dot between double brackets, and the footer. The correctness of the template is then checked with
Using Golang templates may seem like overkill for such a tiny application, but it nevertheless looked like the easiest way to concatenate three strings in a few lines of code. Also, in a web context, you’d probably use templates anyway.
It is important to note here that we need to use the
text/template package so that the HTML tags are not escaped.
In lines 40 and 41, we create an output buffer called
processed of type
bytes.Buffer and render the template into it using
Execute(). The reason we render the HTML page into a byte buffer is so that we can send it to
In lines 43–46, we write the output buffer
processedto a file called
ioutil.WriteFile(). We also check for any errors, should they occur.
The custom renderHook() function
This function is of the
RenderNodeFunc type. You can read about that here.
When the markdown parser is run, it creates a node tree to represent the HTML to be rendered. We can use a custom function to render nodes if we want them to be rendered differently than the default.
In lines 3–15, we process the heading nodes.
In line 4, we get the level of the heading node. We are interested in level 1 as we only wish to adapt the output for the
h1 tag, for this example.
In line 6, we check if the node is a beginning node. This means that the variable
entering should be true. Here we also test if
level equals to 1.
In line 7, we write the output
h1tag as we want it to appear. Check the Bulma documentation for the meaning of the classes. For any other CSS framework, we can do something similar here.
In lines 8 and 9, we again test if
entering is true. This time we deal with the other heading nodes that are not level 1. Again we write the output as we want it. In this case, with no specific classes added to the tag.
In lines 10 and 11,
entering would be false and would thus signify that we are dealing with closing tags. The closing tags are rendered in the same manner for all heading levels. We write this to the output stream.
In line 14, we return from the function with two values. The first value
ast.GoToNext() tells the program to process the next node in the tree. This can be a child node. The second value is a boolean. In this case, the boolean is true because our custom function does the rendering of the tags. If the Standard renderer were the render the tags, the boolean value would be false.
In lines 16–30, we process the image nodes. Note that in this example, we’ll wrap the image (
img) tags in
figure tags This allows us to use some special styling from the Bulma CSS framework.
In line 17, we get the source
src of the image node.
In lines 19 and 20, we find the first child of the image node, which contains the “alt” text. (I discovered this through trial and error).
In lines 22 and 23, we test to see if we are
entering the image node and if the
alt text is not an empty string. We then output the
img tags as we would like them to be; with a few classes in the
figure tag and also with the
alt text in the
In lines 24 and 25, we again test to see if we are
entering an image node but this time the
alt text should be empty. We output the
img tags as we want them to appear but without the
alt text attribute in the
imgtag, as it is blank.
In lines 26 and 27
entering will be false, and we write the ending
figure tag. No
img tag is needed here.
In line 30, we return from the function but with different values than previously. We’ll return
ast.SkipChildren As the first return value, as the children of the image node should not be rendered. This ensures that the
alt text is not rendered as paragraph text in the HTML page. The second value is again true.
In lines 31 and 32, we deal with all other nodes, ie, the nodes that do not represent the heading or image tags. We return from the function with
ast.GoToNext and false. Here we return false as the second value as the default renderer needs to render the tags.