Skip to content

Instantly share code, notes, and snippets.

@cferdinandi
Created August 28, 2023 15:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save cferdinandi/dd9631993d33fd376a37136eb2fb6e4a to your computer and use it in GitHub Desktop.
Save cferdinandi/dd9631993d33fd376a37136eb2fb6e4a to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Code Sandbox</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin: 1em auto;
max-width: 40em;
width: 88%;
}
label,
textarea,
iframe {
display: block;
width: 100%;
}
textarea {
margin-bottom: 1.5em;
min-height: 8em;
}
</style>
</head>
<body>
<h1>Code Sandbox</h1>
<label for="html">HTML</label>
<textarea id="html" spellcheck="false" autocorrect="off" autocapitalize="off" translate="no"></textarea>
<label for="css">CSS</label>
<textarea id="css" spellcheck="false" autocorrect="off" autocapitalize="off" translate="no"></textarea>
<label for="js">JavaScript</label>
<textarea id="js" spellcheck="false" autocorrect="off" autocapitalize="off" translate="no"></textarea>
<p><strong>Result</strong></p>
<iframe id="result"></iframe>
<script>
// Get elements
let html = document.querySelector('#html');
let css = document.querySelector('#css');
let js = document.querySelector('#js');
let result = document.querySelector('#result');
// Store debounce timer
let debounce;
/**
* Update the iframe
*/
function updateIframe () {
// Create new iframe
let clone = result.cloneNode();
result.replaceWith(clone);
result = clone;
// Render
result.contentWindow.document.open();
result.contentWindow.document.writeln(
`${html.value}
<style>${css.value}</style>
<script type="module">${js.value}<\/script>`
);
result.contentWindow.document.close();
}
/**
* Handle input events on our fields
* @param {Event} event The event object
*/
function inputHandler (event) {
// Only run on our three fields
if (
event.target !== html &&
event.target !== css &&
event.target !== js
) return;
// Debounce the rendering for performance reasons
clearTimeout(debounce);
// Set update to happen when typing stops
debounce = setTimeout(updateIframe, 500);
}
// Listen for input events
document.addEventListener('input', inputHandler);
</script>
</body>
</html>
@frumbert
Copy link

Why do you use document.open / close when you could create an object url for the iframe? This will remain performant for larger documents too.

	function updateIframe () {

		// Create new iframe
		let clone = result.cloneNode();
		result.replaceWith(clone);
		result = clone;

		// Render
                let page = [`<!doctype html><html><head><meta charset="utf-8"><style>${css.value}<\/style></head><body>${html.value}<script type="module">${js.value}<\/script></body></html>`];
                const blob = new Blob(page,{type:"text/html"});
                let burl = URL.createObjectURL(blob);
                result.setAttribute("src",burl);
                setTimeout(URL.revokeObjectURL,100,burl);
	}

@cferdinandi
Copy link
Author

@frumbert Oh neat! Didn't know you could do that! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment