Build a browser-based code editor with WebContainers: file tree, editor, terminal, and preview. Use when creating interactive coding environments, building educational tools, or embedding development environments in web apps. Trigger: "webcontainer IDE", "browser IDE", "stackblitz editor", "code playground".
Build a complete browser-based IDE using WebContainers: file explorer, code editor (Monaco/CodeMirror), integrated terminal (xterm.js + jsh), and live preview iframe. This is the architecture behind bolt.new.
<div id="app">
<div id="file-tree"></div>
<div id="editor"></div>
<div id="terminal"></div>
<iframe id="preview"></iframe>
</div>
import { WebContainer, FileSystemTree } from '@webcontainer/api';
const files: FileSystemTree = {
'package.json': {
file: { contents: JSON.stringify({
name: 'playground', type: 'module',
scripts: { dev: 'vite' },
dependencies: { vite: '^5.0.0' },
}) },
},
'index.html': {
file: { contents: '<!DOCTYPE html><html><body><div id="app"></div><script type="module" src="/src/main.js"></script></body></html>' },
},
src: { directory: {
'main.js': { file: { contents: 'document.getElementById("app").innerHTML = "<h1>Hello!</h1>";' } },
}},
};
const wc = await WebContainer.boot();
await wc.mount(files);
async function renderFileTree(path = '/') {
const entries = await wc.fs.readdir(path, { withFileTypes: true });
const tree = document.getElementById('file-tree')!;
for (const entry of entries) {
if (entry.name === 'node_modules') continue;
const fullPath = `${path}${path === '/' ? '' : '/'}${entry.name}`;
const el = document.createElement('div');
el.textContent = entry.isDirectory() ? `📁 ${entry.name}` : `📄 ${entry.name}`;
el.onclick = async () => {
if (!entry.isDirectory()) {
const content = await wc.fs.readFile(fullPath, 'utf-8');
editor.setValue(content); // Monaco editor
currentFile = fullPath;
}
};
tree.appendChild(el);
}
}
let currentFile = '/src/main.js';
// Monaco editor onChange
editor.onDidChangeModelContent(async () => {
const content = editor.getValue();
await wc.fs.writeFile(currentFile, content);
// Vite HMR will auto-reload the preview
});
// Terminal
const jsh = await wc.spawn('jsh', { terminal: { cols: 80, rows: 12 } });
jsh.output.pipeTo(new WritableStream({
write(data) { terminal.write(data); },
}));
// Install and start dev server
const install = await wc.spawn('npm', ['install']);
await install.exit;
await wc.spawn('npm', ['run', 'dev']);
// Preview iframe
wc.on('server-ready', (port, url) => {
document.getElementById('preview')!.src = url;
});
| Error | Cause | Solution |
|---|---|---|
| Preview blank | Server not ready yet | Wait for server-ready event |
| HMR not working | Vite not running | Check npm install succeeded |
| File tree empty | Mount failed | Verify FileSystemTree structure |
For embedding and sharing projects, see stackblitz-core-workflow-b.