ClassyMarkdown – adds classes to your MarkDown content

I just released my first public Kirby plugin! :smiley:

Classy Markdown

A Kirby plugin for adding classes to the markup generated by
the built-in Markdown parser.

What is it good for?

When dealing with complex content, i.e. nested components inside your Markdown-formatted texts, you often face the problem of side effects. To avoid this, a lot of developers use BEM-Naming convention these days. That basically means, that every element you want to target with a CSS-selector has it’s own, unique class.

Info & Download:

If you’re find this useful or at least interesting, I would really appreciate your feedback on this.


This is great! Markdown can be fantastic but it seems like I always need to come up with one workaround or another to get past its limitations. Looking forward to giving this a look!!

Made a huge update, the plugin now covers most markdown features and has better defaults:

Released version 0.2.0 today. ClassyMarkdown ist now compatible with Kirby 2.3.0 (Beta).

Get in from GitHub:

I always “fixed” this by adding a “.kirbytext”-class to the wrapper of the kirbytext markup.

Then I could target those styles in a separate kirbytext.scss file.

I usually do it the same way as you. But for some components, this always causes trouble in my markup. Especially, when having nested components like tabs panes or slideshows, which often use <li> tags. In most cases, it might not be necessary to use all options of ClassyMarkdown. But for stuff like links with an URL as link text or footnotes (a feature of markdown extra), having the possibility of adding classes is very handy.

Components such as “tabs” or “slideshows” would require a separate kirbytag anyway, not?
Then you can incorporate it there.

That’s how I do it anyway; not fighting to be right :slight_smile:

Is there a bug, that links generated with kirbytext, does not get the link classes in kirby version 2.4.0?

Unfortunately, I haven’t tested the plugin in detail with Kirby 2.4 yet. I’ll have a look at it tomorrow.

Okay, it’s been a while since the last update of my plugin, so I had to take a look at the source again … by default, ClassyMarkdown only transforms Markdown. If you also want it to set classes on Kirbytags, you have to override the built-in tags like described in the docs:

# site/tags/link.php
kirbytext::$tags['link'] = array(
  'attr' => array(
  'html' => function($tag) {

    $link = url($tag->attr('link'), $tag->attr('lang'));
    $text = $tag->attr('text');

    if(empty($text)) {
      $text = $link;

    if (str::isURL($text)) {
      $text = url::short($text);

    $class = $tag->attr('class');
    $class .= ' markup--link';

    if (str::isURL($text)) {
      $class .= ' markup--link--url';

    $class = trim($class);

    return html::a($link, $text, array(
      'rel'    => $tag->attr('rel'),
      'class'  => $class,
      'title'  => $tag->attr('title'),
      'target' => $tag->target(),


I did not implement it, because Kirby loads tags within /site/tags/ before loading plugins. Due to this behavior, built-in tags can be overriden by a plugin, but tags defined in a plugin cannot be overridden by tags defined in /site/tags/. However, this could be achieved by checking the tags directory for localized versions of a tag before registering the plugin tags. I.e.: If the file link.php exists within the tags directory, use that tag. Otherwise, register the plugin’s version of the link tag. Do you think, the plugin should to this or are there any pitfalls I did not think of?

Sorry, my fault. I used the kirby tag link and not the native html link syntax [example link]( With the native variant it works like charme.

Yeah, but it might be worth adding the additional classes also to built-in Kirbytags as well, as they provide far more options. I scheduled that for the next update of the plugin. :slight_smile:

Thanks for this plugin, I am gonna try it in the coming days as I began to use functional css.

Was wondering if there is a way to parse and filter a ->kirbytext() output each time we use this function, and do something like:

  • if p, add these classes
  • if ul, add these classes

in general I think your plugin will work well, but I can imagine that sometimes I need to add custom variant only on a specific kirbytext output. And sure, you can create custom scoped css classes for that, but would be curious to know if kirby has a parsing and filtering function like the above anyway.

Hey @afincato,

unfortunately my plugin does not have this functionality, as it is not possible to pass custom parameter to the ->kirbytext() method.

A word of caution, when adding classes to every element: I don’t want to tell you how write proper CSS, but you should consider to be careful when solving everything with class selectors. While functional CSS is very great for doing layout and grid stuff, I would really consider to use context-based selectors for Kirbytext/Markdown styling whenever possible. does sth. like <p class="graf graf--p graf-after--p">, but the downsides of that are a bloated HTML source and also your HTML will become less portable. I always put Kirbytext/Markdown into a wrapper that has a special class, often I just name it .text. This selector does not contain any styling rules, but it makes it much easier to style the content within. You can also have different scopes for different kinds of content, e.g. .text, .small-text or .text .text--small etc. for handling these cases. Doing it that way, you HTML remains portable and you can handle a lot of the complexity in your CSS using child selectors. And with ClassyMarkdown on top, you can still distinguish Kirbytext content from nested modules like e.g. generated by a galllery or linklist Kirbytag.

Have a nice day :sunglasses:

Really nice to hear this from you, as I was indeed considering the pros and cons of styling everything with atomic classes (I tried this approach with a python website I am working on) and I realised that for typography it gets easily messy the situation.

So for once, using scopes and child selectors would be way more of a careful approach!