A good[ish] website
Web development blog, loads of UI and JavaScript topics
Here’s how to build a really simple code demo iframe with Gatsby, which lives outside the site’s main CSS scope.
The nice thing about static site generators like Gatsby is that you can use MDX to write post, which means you can write demos right into the posts with React components. That’s great, but sometimes you want a demo that lives outside the current scope. That can be done with an iframe.
Some requirements we want our demo to meet:
index.mdx
file.The dir structure looks something like this:
posts/
├── code-demo/
│ ├── demo.html
│ └── index.mdx
├── bar-foo.mdx
It would be cool if Gatsby would render HTML files placed into the post dir: posts/code-demo/demo.html
, we could then load them into an iframe: <iframe src='/code-demo/demo.html'/>
. But it doesn’t do that, which is okay, because iframe also has the lesser known attribute srcdoc
, which you can pass an HTML document as a string and it will just render it normally. Neat.
We need to use WebPack’s html-loader
to import HTML files. This is pretty easily done in Gatsby, since Gatsby is essentially a big WebPack config system.
First install it:
npm i --save-dev html-loader
Then export the onCreateWebpackConfig
hook from the gatsby-node.js
file, like so:
// gatsby-node.js
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
module: {
rules: [
{
test: /\.html$/i,
loader: 'html-loader'
}
]
}
})
}
Our simple test demo file looks something like this, just a good old HTML file:
<!-- posts/code-demo/demo.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test demo</title>
<style id="styles">
#foo {
margin-bottom: 10px;
}
.hidden {
visibility: hidden;
}
</style>
</head>
<body>
<button id="foo">Button</button>
<div id="message" class="hidden">💥</div>
</body>
<script id="scripts">
const button = document.getElementById('foo')
const message = document.getElementById('message')
button.addEventListener('click', () => message.classList.toggle('hidden'))
</script>
</html>
Then import it in the MDX post file and put the string into an iframe:
---
title: Code demo
date: 2021-12-28 21:26:44
---
import demo from './demo.html'
Here’s the demo:
<iframe srcdoc={demo} title='Code demo' />
And it renders like this:
There you have it. Check my post on how to make a React iframe component.
It’s just HTML, any imports are not resolved. The ESM import
statement works in modern browsers tho, but if you try to do import foo from './foo'
, it looks from /foo.js
, that would be the static dir, not here in the post dir. But script tags can be used like normal for sure.
I’m planing a post on more elaborate demo system. Probably publishing it within next few days.
Comments would go here, but the commenting system isn’t ready yet, sorry.