Adding custom rendering to HTML elements in 11ty/Build Awesome
The other week, I was thinking how cool it'd be to have a link preview plugin for 11ty (completely static of course!). You'd be able to hover on a link, and it'd give you the title of the page, along with its description etc, perhaps even an archive.org link.
I looked into the anatomy of 11ty plugins, what was needed to make one and what developers have access to. What I needed was simple (or so I thought): A way to inject a span element into any links in the content (not the entire page!) of a post.
I first found 11ty's addTransform function , but I quickly ruled it out because it targets the whole page. I needed something that targeted the rendering of markdown content only.
markdown-it rules and Markdown tokens
Because I'm new(ish) to Eleventy, I thought I'd ask the lovely 11ty veterans on their Discord for some help. Chris very helpfully referred me to his own simplified implementation of Nicolas Hoizey's anchor links code.
Being totally honest, I got a bit lost here... I needed to understand how 11ty renders out Markdown first! 11ty uses markdown-it, a fast and lightweight Markdown parser for JavaScript. From here, I found the documentation and started digging. If I could intercept how markdown-it renders markdown syntax into HTML elements, then I could easily inject the spans I wanted.
From there, I learnt that markdown-it has "rules" which are basically how tokens (pieces of Markdown syntax) render into HTML. For example, if I were to use the bold token in Markdown like this:
**test**
markdown-it then processes that with the strong open and close rules. For example:
md.renderer.rules.strong_open = function () { return '<b>'; };
md.renderer.rules.strong_close = function () { return '</b>'; };
Perfect... If I could somehow intercept the link open or close rule, I could inject my span wherever I wanted in any Markdown link. Armed with the knowledge of markdown-it Chris's solution and Nicolas's both made way more sense, I could now make my own!
The solution
I knew what to do with markdown-it to get what I wanted... But how do I do that in 11ty? Well thankfully, 11ty has an amendLibrary function, this can give you direct access to any libraries used in 11ty to modify their function. This would give me direct access to markdown-it . Perfect!
eleventyConfig.amendLibrary('md', md => {
var defaultRender = md.renderer.rules.link_open || function (tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
return `${defaultRender(tokens, idx, options, env, self)}<span>test</span>`;
};
return md
});
And in 9 lines of code? Everything worked beautifully. Obviously, these are not link previews, but all the code is there to make that possible.
But wait, what happened to truly static link previews?!
Once I figured out how to render out custom rules... I started thinking more about whether I really did want link previews. It sounded kind of clunky, like it'd get in the way of the text, that it'd be an accessibility nightmare. I also got concerned about the build times and impact on link traffic. I'd have to come up with a way to cache previews for already "linked" links in the 11ty site. At which point, the build times get more computationally intensive, with much more opportunities for things to go wrong. And honestly? It sounded like not a great UX anyway.
But what counts the most in all this, is that I learnt something new, and had a lot of fun along the way. Better yet, I get to share with you wonderful folk about how to approach this problem.
PSA:
If anyone really is interested in a link preview plugin for 11ty, if there's enough demand, I'd be tempted to make it. It's just, I don't think I'd use it on any of my own sites.