@jbpark/live-editor
v5.0.0
Published
Interactive UI editor with real-time preview and drag-and-drop. Syncs canvas edits back to source code via AST transforms and renders the preview in an iframe for DOM/CSS isolation (not a security sandbox).
Maintainers
Readme
Live Editor
An interactive editor for building UIs with real-time preview and drag‑and‑drop. Canvas edits are synced back to source code via AST transforms, and the result renders inside an iframe for DOM/CSS isolation. Built with React 19 and TypeScript. See Security Notes — the iframe is not a security sandbox.
📖 Documentation & live demos: https://live-editor-lab.vercel.app
📁 Project Structure
live-editor/
├─ src/
│ ├─ components/
│ │ ├─ context/ # Global state management
│ │ ├─ dnd/ # Drag-and-drop system with editing panels
│ │ │ └─ panel/ # Property panel field editors
│ │ ├─ editor/ # CodeMirror code editor
│ │ ├─ error/ # Error boundary
│ │ ├─ frame/ # iframe/shadow-DOM preview isolation
│ │ └─ preview/ # Isolated preview runtime
│ ├─ pages/
│ │ └─ editor/ # Local development editor (editor + DnD toggle)
│ ├─ utils/
│ │ ├─ ast/ # AST manipulation & code generation
│ │ ├─ tailwind/ # Tailwind theme helpers
│ │ ├─ cache.ts # Bounded LRU cache
│ │ └─ selection.ts # Multi-select helpers
│ ├─ constants/ # Constants and configurations
│ ├─ types/ # TypeScript type definitions
│ └─ main.tsx # Local development app entry
├─ demos/ # Standalone iframe demos for the documentation
├─ website/ # Docusaurus documentation site
└─ package.jsonHow the pieces fit together — the read and write paths, the commit levels and a glossary — is in ARCHITECTURE.md.
🎯 Highlights
- Real-time code updates: Canvas interactions (add/move/remove, property edits) are propagated back to source code safely.
- Interactive property panel: Edit numbers, strings, booleans, arrays, and objects from the side panel.
- Advanced JSX binding system: Automatically detects and enables editing for all JSX element properties (children, label, icon, etc.) through type-based detection.
- Smart Items editor: Manage array items with add/move/delete operations, edit properties and nested JSX components with stable component identity across reorders.
- Preview runtime: Renders compiled output inside an iframe for DOM/CSS isolation (not a security sandbox — see Security Notes).
- Robust drag-and-drop: Powered by
@dnd-kitfor smooth sorting and positioning.
📦 Installation
pnpm add @jbpark/live-editor react react-domreact and react-dom (>= 19) are peer dependencies. prettier (>= 3) is an
optional peer — install it too if you want the editor's format-on-save; without
it the editor still works and simply skips formatting.
🧑💻 Usage
Import the stylesheet once near your app root — it is required and is not imported by the JS entry:
import { useState } from 'react';
import Live from '@jbpark/live-editor';
import '@jbpark/live-editor/style.css';
// required — not imported by the JS entry
const SAMPLE = `
import * as ui from 'ui-kit';
const App = () => (
<div className="flex flex-col items-start gap-2 p-6">
<ui.Typography.Title level={3}>Hello</ui.Typography.Title>
<ui.Button type="primary">Edit me</ui.Button>
</div>
);
export default App;
`;
export default function Example() {
const [code, setCode] = useState(SAMPLE);
return (
<Live>
<Live.Editor value={code} onChange={setCode} />
<Live.Preview showError frame={{ mode: 'iframe', syncStyle: true }} />
</Live>
);
}See the documentation site for the full guide (how Tailwind reaches the preview, custom panels, and more).
🧩 Entry points
The package ships subpath exports so a consumer who needs only one feature area can avoid pulling in the rest (e.g. no CodeMirror in a preview-only build) — see #194:
| Import | Contains |
| ------------------------------------ | ------------------------------------------- |
| @jbpark/live-editor | Everything (Live provider + all surfaces) |
| @jbpark/live-editor/provider | The shared editing context provider only |
| @jbpark/live-editor/dnd | Drag-and-drop canvas + property panel |
| @jbpark/live-editor/editor | CodeMirror code editor |
| @jbpark/live-editor/preview | Isolated preview runtime |
| @jbpark/live-editor/error | Error boundary |
| @jbpark/live-editor/utils | Compile/section helpers |
| @jbpark/live-editor/utils/ast | AST manipulation & code generation |
| @jbpark/live-editor/utils/tailwind | Tailwind theme helpers |
| @jbpark/live-editor/style.css | Compiled stylesheet (required) |
🔒 Security Notes
- The
sandboxprop on the preview<iframe>(src/components/frame/iframe/iframe.tsx) is not a security boundary. Compiled preview code is executed vianew Function(...)in the host page's own JS realm (compileModuleinsrc/utils/compile.ts); only the resulting React elements are portaled into the iframe'scontentDocumentfor DOM/CSS rendering. The iframe itself never evaluates user code. - Practical implication: previewed code runs with the same JS-level access as the host application (cookies, DOM, in-memory state) — the iframe boundary does not contain it.
- Only open/edit projects you trust. Don't use this editor to preview arbitrary third-party project files without adding real isolation yourself (e.g. running compilation inside the iframe's own
contentWindowrealm and communicating results back viapostMessage) — that isolation is not implemented here today.
🧰 Tech Stack
- Core: React 19, TypeScript 6, Vite 8
- DnD:
@dnd-kit/core,@dnd-kit/sortable,@dnd-kit/modifiers - Editor:
@uiw/react-codemirrorwith VSCode theme - UI/Styling:
@jbpark/ui-kit,lucide-react, Tailwind CSS 4 - Transform: Babel (standalone) for in-browser transforms
⚙️ Requirements
- Peer deps:
react >=19,react-dom >=19 - Package metadata declares Node.js
^22.18.0 || >=24.11.0, the range Babel 8 supports. CI checks that the entries meant for Node (utils,utils/ast,utils/tailwind,provider,error) load on Node 22.18. Repository development, builds and the rest of CI use the version pinned in.nvmrc(currently 24.18.0). - pnpm (developing this repo only): the version in
packageManager(currently 12.8.1), managed via Corepack. Installing the package works with any package manager.
🚀 Development (this repo)
Working on Live Editor itself. To use the package in your app, see Installation above. Start with ARCHITECTURE.md for how the code is organized.
pnpm Setup (Recommended)
The pnpm version is pinned by the packageManager field in package.json (and in website/package.json). With Corepack enabled, running pnpm in the repo uses exactly that version, downloading it on first use:
corepack enableOr install the pinned version yourself (npm install -g pnpm@<version>, with the version from packageManager). pnpm 11 and later need Node.js 22 or newer.
Install
pnpm installDevelop
pnpm run devThis starts the local editor at the root route. The public documentation and
feature demos live in website/.
Build
pnpm run buildTest
pnpm testLint & Type Check
pnpm run lint
pnpm exec tsc -bPreview Production Build
pnpm run build:demo
pnpm exec vite preview --outDir dist-demo📦 Versioning & Release
Releases are fully automated via changesets:
- Each PR against
maingets an AI-drafted changeset file describing its change. - Once changesets accumulate on
main, a "Version Packages" PR bumpspackage.json's version and consolidatesCHANGELOG.md. - Merging that PR builds, tags the release, and publishes to npm.
CI workflows:
changeset-draft.yml: Drafts an AI-generated changeset on PR open/sync againstmain.version.yml: Opens/updates the "Version Packages" PR once changesets accumulate.publish.yml: Builds/publishes/tags/creates the GitHub Release on merge tomainwhen the version is untagged.release.yml: Manualworkflow_dispatchfallback to (re)create a GitHub Release for an existing tag.- The Docusaurus documentation site is built from
website/and deployed via Vercel (seevercel.json).
📄 License
MIT License — Copyright (c) 2026 jbpark
