HTML inside Kramdown table cells

1 min read

The question of how to write a list inside of a table cell with Kramdown recently came up in a thread on Jekyll Talk — prompting me to look for a solution.

Unfortunately something like this doesn’t work:

| Fruit         | Price         | Advantages         |
| ------------- | ------------- | ------------------ |
| Bananas       | $1.34         | - built-in wrapper |
|               |               | - bright color     |
| ------------- | ------------- | ------------------ |
| Oranges       | $2.10         | - cures scurvy     |
|               |               | - tasty            |

Kramdown treats each new line as a row and doesn’t render the bullet lists properly in the Banana and Oranges rows as can be seen below.

Bananas$1.34- built-in wrapper
  - bright color
Oranges$2.10- cures scurvy
  - tasty

Throwing HTML at the problem doesn’t quite work either.

| Fruit         | Price         | Advantages         |
| ------------- | ------------- | ------------------ |
| Bananas       | $1.34         | <ul><li>built-in wrapper</li><li>bright color</li></ul> |
| ------------- | ------------- | ------------------ |
| Oranges       | $2.10         | <ul><li>cures scurvy</li><li>tasty</li></ul> |

Instead of rendering the HTML, it is escaped and outputted as a single line of text.

Bananas$1.34<ul><li>built-in wrapper</li><li>bright color</li></ul>
Oranges$2.10<ul><li>cures scurvy</li><li>tasty</li></ul>

What is needed is a way of telling Kramdown to leave the HTML alone and output as is. Thankfully there is such a way using the nomarkdown extension.

Simply wrap the HTML with {::nomarkdown} ... {:/} like so:

| Fruit         | Price         | Advantages         |
| ------------- | ------------- | ------------------ |
| Bananas       | $1.34         | {::nomarkdown}<ul><li>built-in wrapper</li><li>bright color</li></ul>{:/} |
| ------------- | ------------- | ------------------ |
| Oranges       | $2.10         | {::nomarkdown}<ul><li>cures scurvy</li><li>tasty</li></ul>{:/} |

And the table will output as expected1.

  • built-in wrapper
  • bright color
  • cures scurvy
  • tasty

While not as readable as a pure Markdown solution, it gets the job done.

From what I understand Pandoc and RedCarpet have better support for this sort of thing if you want to use their flavor of Markdown.

Since Kramdown is the default renderer used by Jekyll I think I’ll just suck it up and stick with this workaround for now :expressionless:.

  1. Be sure to keep all of your HTML on a single line for this to work properly. 

Enjoyed this content?

Help keep it free by sending a donation or purchasing something from my Amazon Wish List. You can also subscribe to various site feeds to get notified of new posts or follow me on social media.


Willy McAllister on

I have the opposite challenge … getting kramdown to process text inside a <details> tag. I would prefer not to drop into html when writing <details>. The solution I’ve come across is This plugin works great, but it is not supported by github pages, so I have to transfer my whole _site to github. Have you come across a kramdown extension that says “hey kramdown, process me!”.

Michael Rose on

Have you looked at the markdownify filter? I use it to do something similar to place Markdown text inside of a figcaption element.

There’s several ways to handle this without the need of a plugin. You could do something like this with a Liquid capture:

{% capture your_md %}Here is some Markdown you'd like to **capture**.{% endcapture %}

Then inject the captured variable into whatever you want and add the Markdownify filter so Kramdown processes it like so:

  {{ your_md | markdownify }}

Which would give you the following HTML output:

  <p>Here is some Markdown you'd like to <strong>capture</strong>.</p>

If you don’t want to bother with all the captures you could build your own Jekyll include that you could pass text through as a parameter to be Markdownified.

Willy McAllister on

Captures work nicely! I added a summary, and removed the spurious <p> tags so the summary lines up with the open icon.

{% capture summary %}Here is my Markdown *summary*{% endcapture %}
{% capture details %}Here is my Markdown **captured**.{% endcapture %}

    <summary>{{ summary | markdownify | remove: '<p>' | remove: '</p>' }}</summary>
    {{ details | markdownify }}

Leave a comment