Pick a theme:

Interactive demos inside articles

by Lea Rosema

I wanted to embed demo snippets of html/css/js into my articles, so I added a {% demo "demo-name" %} shortcode to my Eleventy blog. Those demos are just plain html files located in src/demos, with everything inline, with the html skeleton provided by Eleventy.

As <style> tags would then be put into the body, I added a html transform rule which moves those <style> tags from <body> to <head>. Although browsers seem to tolerate style tags inside <body>, it would not be valid HTML.

Those html transforms are processed in my Eleventy project at build time using linkedom, which is a lightweight and fast DOM implementation. The code for it is put into a separate eleventy config file which can be loaded into the main configuration file via eleventyConfig.addPlugin.

Using LinkeDOM is pretty straightforward, you have a parseHTML function where you pass-in a string of HTML code and you will get a DOM API back to work with, containing { document, customElements } and more.

So, moving a style tag from head to body on the server-side looks similar to how you would do it in browser-side JavaScript:

// Moves style tags from body up to the head.
module.exports = function ({document}) {
  document.body.querySelectorAll('style').forEach(style => {
    style.remove();
    document.head.appendChild(style);
  });
};

For embedding the demos into my articles, I used a tab widget inside a <figure> element, but that widget shouldn't be included into the rss feed, so I only put links to the demos and added a transform rule which adds the tab widget into the blog articles on the website.

The tab widget follows the pattern of the Example of Tabs with Manual Activation of the ARIA Authoring Practices Guide (APG).

Below is an example of such a demo embed.

<style>
:root {
    color-scheme: dark;
}
</style>

<h1>Hello World!</h1>

That's my first demo.

<script type="module">
import vanillaH from "https://unpkg.com/vanillah?module";
import htm from "https://unpkg.com/htm?module";

const html = htm.bind(vanillaH(document));

const p = html`<p>
    This is a <em>fancy</em> paragraph
    inserted via JavaScript.
</p>`;

document.body.appendChild(p);
</script>
This is my first test of embedding demos into my blog articles.

In a next iteration, I could maybe separate the code into HTML/CSS/JS tabs, similar to what you know from embeds like Codepen or jsfiddle.

The code

anchor

This needs some clean up, I could imagine putting that into an Eleventy plugin. Right now it's sprinkled over all of the code base, but I coded that while I was in hospital during my awake times, only having my iPad with me, laying most of the time in a sickbed.

A sickbed in a hospital with dim lighting. There is a bed-table with an iPad and some headphones on top. The app Working Copy is opened, which is a git client with an integrated text editor with syntax highlighting for iOS.

Links to the code: