Last active
April 17, 2026 21:50
-
-
Save ggorlen/54d729f6022430183512a268efe8d2c0 to your computer and use it in GitHub Desktop.
No JS HTML previewer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en" class="light dark"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>HTML Script Stripper</title> | |
| <style> | |
| :root { color-scheme: light dark; } | |
| body { | |
| margin: 0; | |
| font-family: system-ui, sans-serif; | |
| } | |
| iframe { | |
| width: 100vw; | |
| height: 100vh; | |
| border: none; | |
| } | |
| #overlay { | |
| position: fixed; | |
| inset: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| pointer-events: none; | |
| } | |
| #dropZone { | |
| border: 2px dashed currentColor; | |
| border-radius: 12px; | |
| padding: 32px 48px; | |
| backdrop-filter: blur(6px); | |
| background: rgba(128,128,128,0.1); | |
| pointer-events: all; | |
| transition: 0.2s ease; | |
| } | |
| #dropZone.hidden { | |
| opacity: 0; | |
| transform: scale(0.95); | |
| pointer-events: none; | |
| } | |
| #dropZone.dragover { | |
| transform: scale(1.05); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <iframe id="preview"></iframe> | |
| <div id="overlay"> | |
| <div id="dropZone"> | |
| Drop HTML file or paste to show without scripts | |
| </div> | |
| </div> | |
| <script> | |
| const dropZone = document.getElementById('dropZone'); | |
| const preview = document.getElementById('preview'); | |
| const showOverlay = () => dropZone.classList.remove('hidden'); | |
| const hideOverlay = () => dropZone.classList.add('hidden'); | |
| function sanitizeHTML(html) { | |
| const parser = new DOMParser(); | |
| const doc = parser.parseFromString(html, "text/html"); | |
| // remove dangerous nodes | |
| doc.querySelectorAll( | |
| "script, iframe, object, embed, base, meta[http-equiv]" | |
| ).forEach(el => el.remove()); | |
| // strip dangerous attributes | |
| const walker = document.createTreeWalker( | |
| doc, | |
| NodeFilter.SHOW_ELEMENT, | |
| null | |
| ); | |
| while (walker.nextNode()) { | |
| const el = walker.currentNode; | |
| [...el.attributes].forEach(attr => { | |
| const name = attr.name.toLowerCase(); | |
| const value = attr.value.trim().toLowerCase(); | |
| if (name.startsWith("on")) { | |
| el.removeAttribute(attr.name); | |
| return; | |
| } | |
| if ( | |
| (name === "href" || name === "src" || name === "xlink:href") && | |
| value.startsWith("javascript:") | |
| ) { | |
| el.removeAttribute(attr.name); | |
| return; | |
| } | |
| if (name === "srcdoc") { | |
| el.removeAttribute(attr.name); | |
| } | |
| }); | |
| } | |
| return "<!DOCTYPE html>\n" + doc.documentElement.outerHTML; | |
| } | |
| function loadHTML(html) { | |
| const clean = sanitizeHTML(html); | |
| const blob = new Blob([clean], { type: "text/html" }); | |
| preview.src = URL.createObjectURL(blob); | |
| hideOverlay(); | |
| } | |
| // drag drop | |
| window.addEventListener("dragover", e => { | |
| e.preventDefault(); | |
| showOverlay(); | |
| dropZone.classList.add("dragover"); | |
| }); | |
| window.addEventListener("dragleave", () => { | |
| dropZone.classList.remove("dragover"); | |
| }); | |
| window.addEventListener("drop", e => { | |
| e.preventDefault(); | |
| dropZone.classList.remove("dragover"); | |
| const file = e.dataTransfer.files[0]; | |
| if (!file) return; | |
| const reader = new FileReader(); | |
| reader.onload = e => loadHTML(e.target.result); | |
| reader.readAsText(file); | |
| }); | |
| // paste anywhere | |
| window.addEventListener("paste", e => { | |
| const html = | |
| e.clipboardData.getData("text/html") || | |
| e.clipboardData.getData("text/plain"); | |
| if (html && html.trim().startsWith("<")) { | |
| e.preventDefault(); | |
| loadHTML(html); | |
| } | |
| }); | |
| window.addEventListener("dragenter", showOverlay); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment