
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
local-iframe
Advanced tools
Web component that allows you to render local code sandboxes using iframes and HTML templates.
local-iframe Web component that allows you to render local code sandboxes using iframes and HTML templates.
You may either install and import the package:
npm install local-iframe
// Option 1: simplest, auto-registers as <local-iframe>
import "local-iframe";
// Option 2: import the class, register it yourself, do whatever you want
import { LocalIframe } from "local-iframe/LocalIframe";
window.customElements.define("code-sandbox", LocalIframe);
Or include it via CDN as an ES Module:
<script
type="module"
src="https://cdn.jsdelivr.net/npm/local-iframe@2.1.0/+esm"
></script>
Then, render it in your document, and define all of the markup for the iframe inside a <template>. Here's a simple counter demo:
<local-iframe>
<template>
<button>Increment</button>
<div>Count: <output>0</output></div>
<script>
const button = document.querySelector("button");
const output = document.querySelector("output");
button.addEventListener("click", () => {
output.innerHTML = parseInt(output.innerHTML, 10) + 1;
});
</script>
<style>
button {
padding: 8px;
background-color: transparent;
}
</style>
</template>
</local-iframe>
local-iframe will copy that inner template and render a fully local iframe with this exact HTML, including CSS and JavaScript, producing the following output:
<local-iframe>
<template><!-- omitted for brevity --></template>
<iframe
style="height: 100%; width: 100%; max-width: 100%;"
srcdoc='<!DOCTYPE html><html><head><meta charset="utf-8"><title></title></head><body>
<button>Increment</button>
<div>Count: <output>0</output></div>
<script>
const button = document.querySelector("button");
const output = document.querySelector("output");
button.addEventListener("click", () => {
output.innerHTML = parseInt(output.innerHTML, 10) + 1;
});
</script>
<style>
button {
padding: 8px;
background-color: transparent;
}
</style>
</body></html>'
></iframe
></local-iframe>
All styles and scripts will only affect elements within the iframe itself.
See examples and usage patterns.
When writing web development tutorials, I sometimes want to allow my readers to interact with code demos or see live output, rather than just sharing screenshots and code samples. Some of the best examples of this are in my article on JavaScript events, where readers can click buttons to see events get logged to the console. All of the demos are fully isolated from each other, which greatly simplifies the content authoring experience for me.
It's easy to do this with a service like Codepen, but I don't like the idea of having to maintain my code demos outside my blog on a third-party website and then embedding them in my Markdown, which often loads a lot of extra JavaScript that I don't need.
Instead, local-iframe uses the HTMLIFrameElement.srcdoc attribute to create a fully self-contained iframe based on whatever code you give it, right there in your page. What you see is what you get.
[!NOTE] This originally began as an Eleventy plugin: eleventy-plugin-code-demo.
[!TIP] See also: "Building HTML, CSS, and JS code preview using iframe's srcdoc attribute" by Maciej Mionskowski, which is what originally inspired me to poke around and see how far I could take this idea.
iframe ContentThere are two ways to define the markup for your iframe:
<template> as a child of <local-iframe>.<template> elsewhere in the DOM and reference it by ID.<template>As we've already seen, the simplest way to use local-iframe is to render a <template> as a child:
<local-iframe description="Counter demo">
<template>
<button>Increment</button>
<div>Count: <output>0</output></div>
<script>
const button = document.querySelector("button");
const output = document.querySelector("output");
button.addEventListener("click", () => {
output.innerHTML = parseInt(output.innerHTML, 10) + 1;
});
</script>
<style>
button {
padding: 8px;
background-color: transparent;
}
</style>
</template>
</local-iframe>
template AttributeAlternatively, you can define a <template> elsewhere in the DOM and reference it by ID with the template attribute, like so:
<!-- This is what we want to render in the iframe -->
<template id="my-template">
<h1>Template</h1>
<style>
h1 {
color: red;
}
</style>
</template>
<!-- Reference the ID of the template above with the `template` attribute -->
<local-iframe
template="my-template"
description="External template demo"
></local-iframe>
If you change the template attribute, the underlying iframe will re-render with the new markup.
iframeBy default, local-iframe appends an iframe to its subtree if one does not already exist:
<local-iframe>
<template></template>
<!-- The component adds this automatically for you -->
<iframe srcdoc="..."></iframe>
</local-iframe>
Optionally, you may provide a custom iframe as a child, and that will get used instead:
<local-iframe>
<template></template>
<!-- We'll use this iframe instead of inserting a new one -->
<iframe style="border: solid 1px red"></iframe>
</local-iframe>
This allows you to set custom attributes on the iframe yourself, without having to forward them via a bloated API.
iframe.srcdocBy default, LocalIframe renders an inner iframe whose srcdoc is the following barebones HTML document:
_render(templateHtml) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${this.description}</title>
</head>
<body>${templateHtml}</body>
</html>`;
}
However, if you want to render a custom document that will be shared by all iframes, you can:
LocalIframe,_render method, andLike this:
import { LocalIframe } from "local-iframe/LocalIframe";
class CodeDemo extends LocalIframe {
_render(templateHtml) {
return `<!DOCTYPE html>
<html>
<head><meta charset="utf-8">
<title>${this.description}</title>
<style>body { background-color: red }</style>
</head>
<body>
${templateHtml}
<p>Brought to you by CodeDemo</p>
</body></html>`;
}
}
window.customElements.define("code-demo", CodeDemo);
As expected, your custom class will inherit all public/protected properties, attributes, and methods from LocalIframe.
This way, you don't need to duplicate the shared markup across all of your <template>s.
You can also create as many custom variants as you want using this pattern.
Frames will be initially empty until their content is hydrated. This can cause unwanted vertical layout shifts as the page loads. To fix this, you can reserve an explicit height on each frame with inline styles:
<local-iframe style="height: 400px;"></local-iframe>
You will need to treat local-iframes as block elements for this to work, preferably with inline critical styles in the head of your document:
local-iframe {
display: block;
}
You may also set an explicit width, although doing so is optional:
<local-iframe style="width: 800px; height: 400px;"></local-iframe>
If you do choose to set an explicit width, make sure you also set a max-width to prevent horizontal overflow on narrower devices:
local-iframe {
display: block;
+ max-width: 100%;
}
To force the outer local-iframe element's height to match the height of the inner iframe content, set the fit-content attribute:
<local-iframe fit-content>
<template>
<p>Really</p>
<p>long</p>
<p>content</p>
<p>that</p>
<p>forces</p>
<p>the inner iframe</p>
<p>to scroll.</p>
<p>But since fit-content is set,</p>
<p>this local-iframe will resize itself</p>
<p>to match the inner iframe's height.</p>
</template>
</local-iframe>
[!NOTE] If you also set an inline height on
local-iframelikestyle="height: 200px", thefit-contentattribute will always have the final say. If you later remove thefit-contentattribute, the element will return to the previous height that you set, orautoif one was not previously set.
[!TIP] You may either set attributes via HTML or programmatically in JavaScript.
LocalIframeprovides typed getter/setter properties for each attribute listed in the table below. For example:// these are equivalent localIframe.fitContent = true; localIframe.setAttribute("fit-content", ""); // and so are these localIframe.fitContent = false; localIframe.removeAttribute("fit-content");Any attributes of type
booleanare treated asfalseby default, and the presence of the value is all that matters in your HTML.
| Attribute | Type | Description |
|---|---|---|
template | string | The ID of the <template> element to use for the underlying iframe's content. |
description | string | A title to set on the underlying iframe, for improved accessibility. |
fit-content | boolean | If this attribute is set, the element will size its height to match the height of the inner iframe document content and watch for any changes. |
| Method | Type | Description |
|---|---|---|
_render | (html: string) => string | Method on LocalIframe that takes the incoming template HTML and returns an HTML string to set on the underlying iframe.srcdoc attribute. You can override this method in subclasses to define your own HTML. |
pnpm install to install dev dependencies (Vite).pnpm run dev to start the local dev server.iframe yourself and set its srcdoc? Why is this needed?Sure, nothing is stopping you from doing this:
<iframe srcdoc="<!DOCTYPE html>..."></iframe>
But this is inconvenient for several reasons:
<, >, ", and ' yourself.local-iframe allows you to write the srcdoc as regular HTML, but inside a <template> so that it never runs in the page context. It's basically a helper/decorator web component.
FAQs
Web component that allows you to render local code sandboxes using iframes and HTML templates.
The npm package local-iframe receives a total of 10 weekly downloads. As such, local-iframe popularity was classified as not popular.
We found that local-iframe demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.