AI Code & Component Playground

Interactive online HTML, CSS, and JS code editor sandbox with live instant iframe preview, Tailwind CDN support, console logs, and ZIP exporter.

Interactive Mini-Tools

AI Code & Component Playground

258 views • 122 downloads

⚡ Executive Project Overview

The AI Code & Component Playground is a modern, high-performance web-based code sandbox designed for developers, UI/UX designers, and students to build, test, and prototype HTML5, CSS3, and JavaScript components in real-time. Built with pure client-side architecture, it eliminates the latency of traditional server-rendered editors, offering immediate 60 FPS live preview updates as you type.

🚀

Real-Time Multi-Tab Editor

Independent tabs for HTML, CSS, and JavaScript with line numbers, tab-key indentation support, and debounced auto-rendering into an isolated iframe sandbox.

🎨

Tailwind CSS & Preset Library

Built-in toggle for Tailwind CSS v3 Play CDN along with pre-loaded UI presets including Glassmorphic Cards, Neon Buttons, AI Chat Drawers, and Interactive Counters.

💻

Integrated Console Log Interceptor

Captures `console.log()` calls and uncaught JavaScript runtime errors directly inside an embedded console output drawer with timestamps for instant debugging.

📦

1-Click Single File Export

Instantly bundle your HTML structure, custom CSS styles, Tailwind dependencies, and JS scripts into a standalone `.html` file ready for deployment or sharing.

Key Advantages & Benefits

  • Zero Server Latency: Runs 100% locally in your web browser memory without sending user code to external API servers.
  • Isolated Iframe Security: Code execution takes place inside a sandboxed iframe to prevent global scope contamination.
  • Fully Responsive Layout: Flexible split-pane interface optimized for desktop monitors, laptops, and tablets.
  • Free Open-Source Code: Full source code download available with standard MIT license for personal and commercial projects.

🛠️ How to Use the AI Component Playground

  1. Select a preset from the top toolbar dropdown to load starter code (e.g. Glassmorphic Card or AI Chat).
  2. Switch between the HTML, CSS, and JavaScript tabs to edit your code.
  3. Enable or disable the Tailwind CSS toggle depending on your project requirements.
  4. View your changes automatically update in real time in the live render viewport.
  5. Click Export HTML to save the complete standalone component to your computer.
<!DOCTYPE html>
<html lang="en" class="h-full dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI Code & Component Playground - Live Web Sandbox</title>
    
    <!-- Fonts & Icons -->
    <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600&family=Inter:wght@400;500;600;700;800&family=Outfit:wght@600;700;800&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
    
    <!-- Tailwind CSS CDN -->
    <script src="https://cdn.tailwindcss.com"></script>
    <script>
        tailwind.config = {
            darkMode: 'class',
            theme: {
                extend: {
                    fontFamily: {
                        sans: ['Inter', 'sans-serif'],
                        outfit: ['Outfit', 'sans-serif'],
                        mono: ['Fira Code', 'monospace']
                    }
                }
            }
        }
    </script>
    
    <style>
        body { margin: 0; padding: 0; height: 100vh; overflow: hidden; background-color: #0b0f17; }
        .code-textarea {
            tab-size: 2;
            font-family: 'Fira Code', monospace;
            resize: none;
            outline: none;
            line-height: 1.5;
        }
        .code-textarea::-webkit-scrollbar { width: 6px; height: 6px; }
        .code-textarea::-webkit-scrollbar-track { background: rgba(15, 23, 42, 0.6); }
        .code-textarea::-webkit-scrollbar-thumb { background: rgba(56, 189, 248, 0.2); border-radius: 4px; }
        .code-textarea::-webkit-scrollbar-thumb:hover { background: rgba(56, 189, 248, 0.4); }
    </style>
</head>
<body class="h-full text-slate-100 flex flex-col font-sans select-none">

    <!-- Header Toolbar -->
    <header class="h-14 bg-slate-900/90 backdrop-blur-md border-b border-slate-800/80 px-4 flex items-center justify-between shrink-0 z-30">
        <div class="flex items-center gap-3">
            <div class="w-8 h-8 rounded-lg bg-gradient-to-tr from-cyan-500 to-blue-600 flex items-center justify-center text-slate-950 font-outfit font-extrabold text-base shadow-lg shadow-cyan-500/20">
                ⚡
            </div>
            <div>
                <h1 class="font-outfit font-bold text-sm text-white tracking-wide">AI Code & Component Playground</h1>
                <p class="text-[10px] text-cyan-400 font-mono">Live HTML5 / CSS3 / JS Interactive Web Sandbox</p>
            </div>
        </div>

        <!-- Presets & Actions -->
        <div class="flex items-center gap-2">
            <!-- Preset Component Selector -->
            <select id="presetSelect" class="bg-slate-950 border border-slate-800 text-slate-300 text-xs font-semibold rounded-lg px-3 py-1.5 focus:outline-none focus:border-cyan-500 transition">
                <option value="glass-card">Preset: Glassmorphism Card</option>
                <option value="glowing-btn">Preset: Neon Glowing Button</option>
                <option value="ai-chat">Preset: AI Chat Widget</option>
                <option value="counter">Preset: Interactive Counter</option>
            </select>

            <!-- Library Toggles -->
            <label class="inline-flex items-center gap-1.5 bg-slate-950/80 border border-slate-800/80 px-2.5 py-1 rounded-lg text-xs font-semibold text-slate-300 cursor-pointer hover:border-cyan-500/40 transition">
                <input type="checkbox" id="tailwindToggle" checked class="rounded border-slate-700 text-cyan-500 focus:ring-0">
                <span>Tailwind CSS</span>
            </label>

            <button id="runBtn" class="px-3.5 py-1.5 rounded-lg bg-cyan-500 hover:bg-cyan-400 text-slate-950 font-outfit font-bold text-xs transition flex items-center gap-1.5 shadow-md shadow-cyan-500/20">
                <i class="fa-solid fa-play"></i>
                <span>Run</span>
            </button>

            <button id="downloadBtn" class="px-3.5 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 text-white font-outfit font-bold text-xs transition flex items-center gap-1.5 border border-slate-700">
                <i class="fa-solid fa-download"></i>
                <span>Export HTML</span>
            </button>
        </div>
    </header>

    <!-- Main Playground Body -->
    <div class="flex-1 flex flex-col md:flex-row min-h-0 overflow-hidden relative">
        
        <!-- Left Column: Code Editors (HTML, CSS, JS) -->
        <div class="w-full md:w-1/2 flex flex-col border-r border-slate-800/80 bg-slate-950 shrink-0">
            <!-- Tab Switcher Header -->
            <div class="flex items-center bg-slate-900/60 border-b border-slate-800/80 text-xs font-bold shrink-0">
                <button id="tabHtml" class="tab-btn px-4 py-2.5 text-cyan-400 border-b-2 border-cyan-500 bg-slate-900/80 flex items-center gap-2 transition">
                    <i class="fa-brands fa-html5 text-orange-500"></i> HTML
                </button>
                <button id="tabCss" class="tab-btn px-4 py-2.5 text-slate-400 hover:text-white border-b-2 border-transparent flex items-center gap-2 transition">
                    <i class="fa-brands fa-css3-alt text-blue-500"></i> CSS
                </button>
                <button id="tabJs" class="tab-btn px-4 py-2.5 text-slate-400 hover:text-white border-b-2 border-transparent flex items-center gap-2 transition">
                    <i class="fa-brands fa-js text-yellow-400"></i> JavaScript
                </button>
                <div class="ml-auto pr-3 text-[11px] font-mono text-slate-500">
                    <span id="autoRunStatus" class="inline-flex items-center gap-1 text-emerald-400">
                        <span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-ping"></span> Live Sync
                    </span>
                </div>
            </div>

            <!-- Editor Textareas Container -->
            <div class="flex-1 relative bg-slate-950 overflow-hidden">
                <!-- HTML Editor -->
                <textarea id="htmlEditor" class="code-textarea absolute inset-0 w-full h-full p-4 bg-slate-950 text-slate-200 text-xs leading-relaxed border-0" spellcheck="false" placeholder="<!-- Enter HTML Here -->"></textarea>
                
                <!-- CSS Editor -->
                <textarea id="cssEditor" class="code-textarea absolute inset-0 w-full h-full p-4 bg-slate-950 text-slate-200 text-xs leading-relaxed border-0 hidden" spellcheck="false" placeholder="/* Enter CSS Here */"></textarea>
                
                <!-- JS Editor -->
                <textarea id="jsEditor" class="code-textarea absolute inset-0 w-full h-full p-4 bg-slate-950 text-slate-200 text-xs leading-relaxed border-0 hidden" spellcheck="false" placeholder="// Enter JavaScript Here"></textarea>
            </div>
        </div>

        <!-- Right Column: Live Iframe Preview & Console Output -->
        <div class="w-full md:w-1/2 flex flex-col bg-slate-900 shrink-0">
            <!-- Preview Sub-header -->
            <div class="h-9 bg-slate-950/80 border-b border-slate-800/80 px-4 flex items-center justify-between text-xs font-bold shrink-0">
                <span class="text-slate-400 flex items-center gap-2">
                    <span class="w-2 h-2 rounded-full bg-cyan-400 animate-pulse"></span> Live Render Viewport
                </span>
                <div class="flex items-center gap-2">
                    <button id="clearConsoleBtn" class="text-[11px] font-mono text-slate-400 hover:text-rose-400 transition">Clear Console</button>
                    <button id="fullscreenBtn" class="text-slate-400 hover:text-white transition" title="Toggle Fullscreen">
                        <i class="fa-solid fa-expand"></i>
                    </button>
                </div>
            </div>

            <!-- Live Output Iframe Container -->
            <div class="flex-1 bg-white relative overflow-hidden">
                <iframe id="previewIframe" class="w-full h-full border-0 bg-slate-950"></iframe>
            </div>

            <!-- Mini Console Output Log Drawer -->
            <div class="h-28 bg-slate-950 border-t border-slate-800/80 flex flex-col font-mono text-[11px] shrink-0">
                <div class="h-6 bg-slate-900/60 border-b border-slate-800/80 px-3 flex items-center justify-between text-slate-400 font-sans font-bold text-[10px] tracking-wider uppercase">
                    <span>Console Logs & Output</span>
                    <span id="logCount" class="text-cyan-400 font-mono">0 logs</span>
                </div>
                <div id="consoleLogContainer" class="flex-1 p-3 space-y-1 overflow-y-auto text-slate-300 select-text">
                    <div class="text-slate-500 italic">[System] Sandbox initialized. Output logs will appear here...</div>
                </div>
            </div>
        </div>

    </div>

    <!-- JavaScript Execution & Interactive Logic -->
    <script>
        const htmlEditor = document.getElementById('htmlEditor');
        const cssEditor = document.getElementById('cssEditor');
        const jsEditor = document.getElementById('jsEditor');
        const previewIframe = document.getElementById('previewIframe');
        const tailwindToggle = document.getElementById('tailwindToggle');
        const presetSelect = document.getElementById('presetSelect');
        const consoleLogContainer = document.getElementById('consoleLogContainer');
        const logCount = document.getElementById('logCount');

        let currentLogsCount = 0;

        // Presets Library
        const presets = {
            'glass-card': {
                html: `<div class="min-h-screen bg-slate-950 flex items-center justify-center p-6">
  <div class="max-w-sm w-full bg-slate-900/80 backdrop-blur-xl border border-slate-800 rounded-3xl p-6 shadow-2xl text-center space-y-4 relative overflow-hidden group">
    <div class="w-16 h-16 rounded-2xl bg-cyan-500/10 border border-cyan-500/20 text-cyan-400 flex items-center justify-center text-3xl mx-auto group-hover:scale-110 transition duration-300">
      ⚡
    </div>
    <h2 class="font-outfit font-extrabold text-2xl text-white">AI Component Card</h2>
    <p class="text-slate-400 text-xs leading-relaxed">
      A sleek glassmorphism UI card component created with Tailwind CSS and responsive micro-interactions.
    </p>
    <button onclick="triggerAction()" class="w-full py-3 rounded-xl bg-gradient-to-r from-cyan-500 to-blue-600 hover:from-cyan-400 hover:to-blue-500 text-slate-950 font-bold text-xs tracking-wider uppercase transition shadow-lg shadow-cyan-500/20">
      Execute Action
    </button>
  </div>
</div>`,
                css: `/* Custom CSS Glassmorphism Highlights */
body { font-family: 'Inter', sans-serif; }
.group:hover { border-color: rgba(6, 182, 212, 0.4); }`,
                js: `function triggerAction() {
  console.log("Action button clicked!");
  alert("AI Component Interactive Action Triggered Successfully!");
}`
            },
            'glowing-btn': {
                html: `<div class="min-h-screen bg-slate-950 flex items-center justify-center gap-4 p-6">
  <button onclick="btnClick('Cyan')" class="glow-btn px-6 py-3 rounded-2xl bg-cyan-500 text-slate-950 font-bold text-xs uppercase tracking-wider transition hover:scale-105">
    Glowing Cyan
  </button>
  <button onclick="btnClick('Purple')" class="glow-btn-purple px-6 py-3 rounded-2xl bg-purple-600 text-white font-bold text-xs uppercase tracking-wider transition hover:scale-105">
    Neon Purple
  </button>
</div>`,
                css: `.glow-btn {
  box-shadow: 0 0 20px rgba(6, 182, 212, 0.5);
}
.glow-btn-purple {
  box-shadow: 0 0 20px rgba(168, 85, 247, 0.5);
}`,
                js: `function btnClick(type) {
  console.log(type + " glowing button activated!");
}`
            },
            'ai-chat': {
                html: `<div class="min-h-screen bg-slate-950 flex items-center justify-center p-4">
  <div class="w-full max-w-md bg-slate-900 border border-slate-800 rounded-3xl overflow-hidden shadow-2xl flex flex-col h-[400px]">
    <div class="p-4 bg-slate-950 border-b border-slate-800 flex items-center gap-3">
      <div class="w-3 h-3 rounded-full bg-emerald-400 animate-pulse"></div>
      <span class="font-bold text-xs text-white">AI Assistant Chat</span>
    </div>
    <div id="chatMessages" class="flex-1 p-4 space-y-3 overflow-y-auto text-xs text-slate-300">
      <div class="bg-slate-800/60 p-3 rounded-2xl max-w-[80%]">Hello! How can I assist your coding today?</div>
    </div>
    <div class="p-3 bg-slate-950 border-t border-slate-800 flex gap-2">
      <input type="text" id="userInput" placeholder="Ask AI..." class="flex-1 bg-slate-900 border border-slate-800 text-xs rounded-xl px-3 py-2 text-white focus:outline-none focus:border-cyan-500">
      <button onclick="sendMessage()" class="px-4 py-2 bg-cyan-500 text-slate-950 font-bold rounded-xl text-xs">Send</button>
    </div>
  </div>
</div>`,
                css: `::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-thumb { background: rgba(56,189,248,0.2); border-radius: 4px; }`,
                js: `function sendMessage() {
  const input = document.getElementById('userInput');
  const text = input.value.trim();
  if (!text) return;
  
  const chat = document.getElementById('chatMessages');
  chat.innerHTML += \`<div class="bg-cyan-500/10 border border-cyan-500/20 text-cyan-300 p-3 rounded-2xl max-w-[80%] ml-auto">\${text}</div>\`;
  console.log("User query sent:", text);
  input.value = '';
  
  setTimeout(() => {
    chat.innerHTML += \`<div class="bg-slate-800/60 p-3 rounded-2xl max-w-[80%]">Received "\${text}". AI Processing complete!</div>\`;
    chat.scrollTop = chat.scrollHeight;
  }, 600);
}`
            },
            'counter': {
                html: `<div class="min-h-screen bg-slate-950 flex flex-col items-center justify-center p-6 text-center space-y-6">
  <div class="p-8 rounded-3xl bg-slate-900 border border-slate-800 space-y-4 shadow-2xl">
    <span class="text-xs font-bold uppercase tracking-wider text-cyan-400">Interactive Counter State</span>
    <h1 id="countVal" class="text-6xl font-extrabold text-white font-mono">0</h1>
    <div class="flex gap-3">
      <button onclick="updateCount(-1)" class="px-5 py-2.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-white font-bold text-sm">- Decrease</button>
      <button onclick="updateCount(0)" class="px-5 py-2.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-400 font-bold text-sm">Reset</button>
      <button onclick="updateCount(1)" class="px-5 py-2.5 rounded-xl bg-cyan-500 hover:bg-cyan-400 text-slate-950 font-bold text-sm">+ Increase</button>
    </div>
  </div>
</div>`,
                css: `/* Counter Styling */`,
                js: `let count = 0;
function updateCount(val) {
  if (val === 0) count = 0;
  else count += val;
  document.getElementById('countVal').innerText = count;
  console.log("Current count:", count);
}`
            }
        };

        // Load Initial Preset
        function loadPreset(key) {
            if (presets[key]) {
                htmlEditor.value = presets[key].html;
                cssEditor.value = presets[key].css;
                jsEditor.value = presets[key].js;
                updateSandbox();
            }
        }

        // Render Sandbox Output
        function updateSandbox() {
            const html = htmlEditor.value;
            const css = cssEditor.value;
            const js = jsEditor.value;
            const useTailwind = tailwindToggle.checked;

            const tailwindScript = useTailwind ? '<script src="https://cdn.tailwindcss.com"><\/script>' : '';

            const source = `
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@600;700;800&display=swap" rel="stylesheet">
    ${tailwindScript}
    <style>
        ${css}
    </style>
</head>
<body class="bg-slate-950 text-slate-100">
    ${html}
    <script>
        // Console Interception
        const _log = console.log;
        console.log = function(...args) {
            _log(...args);
            window.parent.postMessage({ type: 'CONSOLE_LOG', data: args.join(' ') }, '*');
        };
        window.onerror = function(msg, url, line) {
            window.parent.postMessage({ type: 'CONSOLE_ERROR', data: 'Error: ' + msg + ' (Line ' + line + ')' }, '*');
        };
        ${js}
    <\/script>
</body>
</html>`;

            const iframeDoc = previewIframe.contentDocument || previewIframe.contentWindow.document;
            iframeDoc.open();
            iframeDoc.write(source);
            iframeDoc.close();
        }

        // Listen for Console Logs from Iframe
        window.addEventListener('message', (event) => {
            if (event.data && (event.data.type === 'CONSOLE_LOG' || event.data.type === 'CONSOLE_ERROR')) {
                const isError = event.data.type === 'CONSOLE_ERROR';
                const div = document.createElement('div');
                div.className = isError ? 'text-rose-400 font-semibold' : 'text-cyan-300';
                div.innerHTML = `<span class="text-slate-500">[' + new Date().toLocaleTimeString() + ']</span> ` + event.data.data;
                consoleLogContainer.appendChild(div);
                consoleLogContainer.scrollTop = consoleLogContainer.scrollHeight;

                currentLogsCount++;
                logCount.innerText = currentLogsCount + ' logs';
            }
        });

        // Tab Switching Logic
        const tabHtml = document.getElementById('tabHtml');
        const tabCss = document.getElementById('tabCss');
        const tabJs = document.getElementById('tabJs');

        function switchTab(activeTab, showEditor) {
            [tabHtml, tabCss, tabJs].forEach(t => {
                t.classList.remove('text-cyan-400', 'border-cyan-500', 'bg-slate-900/80');
                t.classList.add('text-slate-400', 'border-transparent');
            });
            activeTab.classList.add('text-cyan-400', 'border-cyan-500', 'bg-slate-900/80');
            activeTab.classList.remove('text-slate-400', 'border-transparent');

            [htmlEditor, cssEditor, jsEditor].forEach(e => e.classList.add('hidden'));
            showEditor.classList.remove('hidden');
        }

        tabHtml.addEventListener('click', () => switchTab(tabHtml, htmlEditor));
        tabCss.addEventListener('click', () => switchTab(tabCss, cssEditor));
        tabJs.addEventListener('click', () => switchTab(tabJs, jsEditor));

        // Auto-update on typing with debounce
        let timer = null;
        [htmlEditor, cssEditor, jsEditor].forEach(editor => {
            editor.addEventListener('input', () => {
                clearTimeout(timer);
                timer = setTimeout(updateSandbox, 300);
            });
        });

        tailwindToggle.addEventListener('change', updateSandbox);
        presetSelect.addEventListener('change', (e) => loadPreset(e.target.value));
        document.getElementById('runBtn').addEventListener('click', updateSandbox);

        document.getElementById('clearConsoleBtn').addEventListener('click', () => {
            consoleLogContainer.innerHTML = '<div class="text-slate-500 italic">[System] Console cleared.</div>';
            currentLogsCount = 0;
            logCount.innerText = '0 logs';
        });

        // Export as HTML File
        document.getElementById('downloadBtn').addEventListener('click', () => {
            const fullCode = `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Exported Component</title>
    ${tailwindToggle.checked ? '<script src="https://cdn.tailwindcss.com"><\/script>' : ''}
    <style>
${cssEditor.value}
    </style>
</head>
<body>
${htmlEditor.value}
<script>
${jsEditor.value}
<\/script>
</body>
</html>`;
            const blob = new Blob([fullCode], { type: 'text/html' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'component-playground-export.html';
            a.click();
            URL.revokeObjectURL(url);
        });

        // Fullscreen Toggle
        document.getElementById('fullscreenBtn').addEventListener('click', () => {
            if (!document.fullscreenElement) {
                previewIframe.requestFullscreen().catch(err => alert(err.message));
            } else {
                document.exitFullscreen();
            }
        });

        // Init Default
        loadPreset('glass-card');
    </script>
</body>
</html>
/* Supports both Dark and Light mode via Tailwind class variant */
// Interactive scripts included inside demo view file

Related Projects

Interactive Drag & Drop Kanban Task Board

Featured

A clean Trello-style Kanban board built with HTML5 HTML Drag and Drop API, color-coded task priorities, and local storage state persistence.

Interactive Mini-Tools • 60

CSS Glassmorphism & Gradient Code Generator

Featured

An interactive visual CSS generator tool to tweak backdrop blur, opacity, transparency, and background gradients with instant 1-click code copying.

Interactive Mini-Tools • 96

Markdown Live Preview Editor & PDF Exporter

Featured

A split-screen markdown writing tool rendering styled HTML live as you type with one-click HTML copy export.

Interactive Mini-Tools • 75