HTML inside Kramdown table cells with Jekyll

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 the following Markdown table 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.

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 generating HTML, the unordered list markup is escaped and outputted as a single line of text.

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.

By wrapping HTML (in this case the <ul>..</ul> elements) with {::nomarkdown} ... {:/}:

| 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>{:/} |

The table will output as expected1.

FruitPriceAdvantages
Bananas$1.34
  • built-in wrapper
  • bright color
Oranges$2.10
  • 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 instead.

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


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

3 mentions

  1. Willy McAllister

    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 Adding support for HTML5’s details element to Jekyll.

    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!”

  2. Michael Rose

    message: “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:

    <details>
      {{ your_md | markdownify }}
    </details>

    Which would give you the following HTML output:

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

    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.

  3. Willy McAllister

    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 %}
    
    <details>
      <summary>
        {{ summary | markdownify | remove: '<p>' | remove: '</p>' }}
      </summary>
      {{ details | markdownify }}
    </details>

Related

Using SSI to detect cookies

In my never ending quest to micro-optimize the hell out of my site, I ran into a snag when trying to use SSI directives to improve the loading of critical CSS and cached stylesheets.