A lightweight, secure, single-file HTML playground hosted via GitHub Pages.
Split editor and live preview environment similar to online HTML compilers — fully self-contained, open source, and sandboxed for safety. Mobile-first design with full-screen Code/Preview toggle on phones and tablets.
- Split-pane layout (editor + preview) with draggable divider
- Mobile-first full-screen mode — toggle between Code and Preview via bottom bar
- HTML / CSS / JS tabs
- Manual Run button with optional Auto-run
- Console panel with collapse/expand, copy, and clear
- Light / Dark theme toggle (persisted across sessions)
- External CDN libraries supported
- LocalStorage persistence for code and preferences
- Hard Reset Preview to kill runaway scripts
- Single
index.htmlfile — no build step, no backend
Open index.html in any modern browser. That is it.
- Create a repository (or fork this one)
- Add
index.html - Commit and push
- Go to Settings > Pages > Deploy from branch > main / root
- Visit your GitHub Pages URL
The preview runs inside a sandboxed iframe with restricted capabilities.
What the sandbox blocks:
allow-same-originis not granted — the preview cannot access the parent page DOM, cookies, or localStorage- Form submissions are blocked
- Top-level navigation is blocked
- Popups are blocked
Content Security Policy (CSP) is injected into every preview document to control resource loading:
| Directive | Value | Purpose |
|---|---|---|
default-src |
'none' |
Deny everything by default |
script-src |
'unsafe-inline' https: |
Allow inline scripts and HTTPS CDN scripts |
style-src |
'unsafe-inline' https: |
Allow inline styles and HTTPS CDN stylesheets |
img-src |
data: blob: https: |
Allow images from data URIs, blobs, and HTTPS |
connect-src |
https: |
Allow fetch/XHR to HTTPS endpoints |
form-action |
'none' |
Block all form submissions |
frame-ancestors |
'none' |
Prevent framing of preview content |
Console bridge security: The postMessage listener verifies that incoming messages originate from the preview iframe contentWindow before processing, preventing spoofed console messages from other sources.
- External scripts are allowed. Because
script-srcpermits any HTTPS source, user code can load and execute arbitrary remote JavaScript. This is by design for a personal/educational tool. If you are adapting this for a multi-tenant platform, restrictscript-srcto specific CDN domains. connect-src https:is broad. Preview code can make network requests to any HTTPS endpoint. This enables APIs and fetch-based workflows but means untrusted code could exfiltrate data visible within the iframe sandbox.- HTML merging uses regex. The function that injects CSP and the console bridge into user HTML uses regular expressions to locate head, body, etc. Edge cases (e.g., those strings inside HTML comments or attribute values) could cause misinjection. Low risk for typical usage.
When loading third-party scripts via CDN, consider using Subresource Integrity (SRI) hashes to ensure the file has not been tampered with.
Code is stored across three tabs (HTML, CSS, JS). All state — including code, active tab, divider position, theme, console state, and auto-run preference — is persisted to localStorage.
When Run is clicked (or auto-triggered on edit):
- HTML, CSS, and JS from the three tabs are merged into a single document
- A Content Security Policy meta tag is injected into head
- A console bridge script is injected into body (overrides console.log/warn/error to forward messages to the parent via postMessage)
- The merged document is assigned to
iframe.srcdoc
The console captures log, warn, error, and unhandled promise rejections from the preview. Features include:
- Collapse / Expand — click the console header to toggle
- Copy — copies all console output as formatted text
- Clear — wipes the console log
- Color-coded levels — INFO, WARN, ERROR each have distinct styling
Click the sun/moon toggle in the header to switch between light and dark themes. The preference is saved to localStorage and restored on next visit. Theming is implemented entirely through CSS custom properties.
If user code contains infinite loops, heavy CPU tasks, or blocking operations, click Reset Preview. This completely replaces the iframe element in the DOM, immediately terminating all execution inside it.
Include CDN scripts directly in the HTML tab. They load inside the sandboxed preview and are subject to the CSP.
- No file system access
- No npm/package manager support
- No TypeScript compilation
- No backend execution
- Infinite loops cannot be gracefully interrupted (must reset iframe)
- Single-file architecture means no multi-file project support
This is intentionally a pure client-side tool.
The entire application is a single index.html file plus this README. Single file by design.
- Mobile full-screen mode — on screens ≤820px, editor and preview are full-screen views toggled via a segmented control in a fixed bottom bar (replaces the stacked split layout)
- Mobile bottom bar — Code/Preview toggle, Run button, console toggle with log count badge, and a More menu for Auto-run, Reset Preview, Reset to Starter, and New Project
- Run + switch — tapping Run on mobile automatically switches to full-screen preview
- Preview on tap — switching to Preview auto-runs the code so the output is always fresh
- Safe area support — bottom bar respects
env(safe-area-inset-bottom)for devices with home indicators (iPhone X and later) - Viewport lock —
maximum-scale=1, user-scalable=noprevents iOS double-tap zoom on the textarea - Larger mobile editor font — textarea bumped to 14px on mobile for readability
- Console badge — log count badge on the mobile console button shows how many messages have been captured
- Mobile More menu — overlay menu provides access to all secondary actions (Auto-run, Reset Preview, Reset to Starter, New Project)
- Synced autorun — desktop and mobile Auto-run checkboxes stay in sync
- Desktop unchanged — side-by-side layout, draggable divider, and all header controls remain identical
- Select All toast — "Selected!" feedback when clicking the Select All button
- iPad / tablet support — editor and preview stack vertically in portrait orientation (≤820px)
- Mobile layout — compact header, hidden button labels, and smaller controls at ≤600px
- Touch-friendly divider — 12px hit target on touch devices, works both horizontal and vertical
- Keyboard shortcuts — Tab inserts 2 spaces, Ctrl/Cmd+Enter runs code, Ctrl/Cmd+S prevented
- Orientation handling — layout re-applies correctly on device rotation
- Safari drag fix — added
-webkit-user-selectfor stable divider dragging - 100dvh support — proper viewport height on mobile browsers with address bars
- Scrollable header — header scrolls horizontally on narrow screens instead of overflowing
- Light / dark theme — toggle with animated sun/moon icon, persisted to localStorage
- Console panel — collapsed by default, expand to view logs, copy output with toast feedback
- Copy button toast — "Copied!" tooltip animation on editor copy
- Console copy toast — "Copied!" feedback with checkmark icon swap
- New Project dialog — confirmation modal with overlay click and Escape key to dismiss
- Clear tab button — clears the active tab's code
- Reset code button — resets all tabs to the starter template
- Hard reset preview — recreates iframe to kill runaway scripts
- Footer — displays version number
- Initial release — single-file HTML playground
- Split-pane editor — draggable divider between code editor and live preview
- Three-tab editor — HTML, CSS, and JS tabs with localStorage persistence
- Live preview — renders via
iframe.srcdocwith merged HTML/CSS/JS - Auto-run mode — optional 400ms debounced auto-execution on input
- Console capture — intercepts
console.log,warn,errorviapostMessagebridge - Sandboxed iframe —
allow-scriptsonly, noallow-same-origin - Content Security Policy — injected CSP restricts resource loading in preview
- XSS protection —
escapeHtml()sanitizes all console output including backticks - Strict mode — all JavaScript runs under
"use strict" - Source verification —
postMessagelistener validatesev.sourceagainst iframe - Starter template — default HTML/CSS/JS demo code on first load
Contributions are welcome. Please open an issue first to discuss any significant changes.
MIT — use freely for personal, educational, or commercial purposes.