Skip to content
| Marketplace
Sign in
Visual Studio Code>Visualization>Visual Code EditorNew to Visual Studio Code? Get it now.
Visual Code Editor

Visual Code Editor

Zahraa mohammed resen

|
2 installs
| (0) | Free
A Figma-like visual editor for real web code. Select elements in your running site, edit them visually, and the source code updates.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Visual Code Editor

A Figma-like visual editor for real web code. Open your project, start the dev server, and edit the running site visually. Every change goes straight into your source files: Tailwind classes, inline styles, JSX/Vue/HTML text and structure.

This is not a mockup tool. The canvas is your real app, served by your real dev server, and the code it writes is the code you ship.

How it works

  1. Open a web project (Next.js, React + Vite, Vue, plain HTML…) in VS Code.
  2. The Visual Code Editor sidebar detects the stack (framework, TypeScript, Tailwind, package manager).
  3. Click Open Visual Editor (or ⌘⌥V / Ctrl+Alt+V). The extension connects to your running dev server, or starts it for you, and shows the site on a canvas.
  4. Click any element and work directly on the canvas: select → drag → resize → align → style → preview → apply. The source updates and hot-reloads instantly.
  5. Undo/Redo (⌘Z / ⇧⌘Z) freely. Every change is listed in Changes with its code diff.
┌──────────────────────────────────────────────────────────────────┐
│ Design│Code · tools · +Add · undo · URL · viewport · scope · zoom │
│ rulers · grid · outline · snap · focus · Compare · Changes · AI  │
├───────────────────────────────────────────────────────┬──────────┤
│  ┌ ruler ───────────────────────────────┐             │ Contextual│
│  │      ┌ floating toolbar ┐            │  ◂ drag ▸   │ properties│
│  │      [ selected element ]  ← handles │  frame width│ (Advanced │
│  │        padding · gap · distances     │             │ collapsed)│
│  └──────────────────────────────────────┘             │           │
├───────────────────────────────────────────────────────┴──────────┤
│ Connection · stack · breakpoint scope · breadcrumbs · status     │
└──────────────────────────────────────────────────────────────────┘

Automatic dev server

When you run Open Visual Editor, the extension resolves the preview URL for the current workspace before connecting. After that the editor behaves exactly as with any other URL.

  1. Explicit URL first. If visualCodeEditor.devServerUrl is set (or you used Open Visual Editor at URL…), that URL is used as-is and is never replaced by detection. If it isn't responding yet, the preview keeps retrying until it does.
  2. Existing server reuse. Otherwise the extension looks for a dev server that is already running for this project: a listening process whose working directory is inside the workspace, on any port. If found, it connects to it and never stops it. On systems where processes can't be inspected (e.g. Windows), it falls back to probing common ports.
  3. Automatic startup. If nothing is running, it starts the project's own script (dev, then start, then serve) with the detected package manager (npm run dev, pnpm dev, yarn dev, bun run dev) in the Visual Editor · Dev Server terminal. Set visualCodeEditor.devCommand to use a different command.
  4. Actual URL and readiness. The real URL is read from the server's output (e.g. Vite moving to 5174 when 5173 is taken), and the editor connects only once the server responds. If another app shares the port on a different loopback address, the exact address is used (e.g. http://[::1]:5173).

Ownership. A server started by the extension is stopped by Stop Dev Server and when VS Code closes. A server you started yourself is left running. The sidebar shows which is which: (started by Visual Editor) or (existing server).

Troubleshooting. If the server can't be found or started, the error names the detected framework, the command, and the last lines of its output. Show Details opens the full log (Visual Code Editor output channel) and the dev server terminal. To connect manually, start your server and set visualCodeEditor.devServerUrl (e.g. http://localhost:3000), or choose Enter URL…. If the project needs a non-standard command (monorepo filters, custom scripts), set visualCodeEditor.devCommand.

Features

Pages, Layers & Assets (left sidebar, like Figma)

  • Layers tab: the project's Pages on top — click one to open it on the canvas (the current page has a ✓). Pages are found from the router: Next.js app/ and pages/, Nuxt pages/, SvelteKit src/routes, Astro src/pages, static .html files, and path entries of react-router / vue-router. Dynamic routes (/blog/[slug], /users/:id) ask for the value first. + creates a new page file (undoable). Below it, the layer tree of the current page.
  • Assets tab: the project's Components (click selects their instances on the canvas, double-click opens the file), Icons & logos, Images and Videos with thumbnails. Double-click an asset (or Use) to set it as the selected image's src or as a background image; files that aren't served yet are copied to public/images.
  • Shortcuts: ⌥1 Layers, ⌥2 Assets, ⌘\ show/hide the sidebar.

Direct manipulation canvas

  • Select with a click, ⇧-click to multi-select (3 selected), ⌘/Ctrl-click to select exactly the element under the pointer. Clicking the text or icon inside a button selects the button; an inline <strong> selects its paragraph. Hover shows name and size; components are purple, elements blue.
  • Breadcrumb (Button › Card › Features › Section) at the bottom of the canvas: click any level to select it.
  • “Why can’t I move this?” — when the layout controls an element (Flexbox, Grid, page flow, a lock), dragging it explains why in plain words and offers the real options: Adjust gap, Adjust alignment, Move left/right, Change columns & rows, Open in Code.
  • Drag an element to change its spacing (margin) with live distance measurements and equal-spacing snapping, drag past a sibling to reorder, or drop it into another container. Moving into a container opens a confirmation (Move Button “Start for free” · From: Section → To: Frame) with the proposed diff and a canvas Preview before anything is written.
  • Resize with Figma handles and live W × H: ⇧ keeps the aspect ratio, ⌥ resizes from the center, ⌘ toggles snapping. Edges snap to siblings, the parent, guides, and to Fill (100%) / Hug (auto).
  • Padding and margin: drag the green (padding) and orange (margin) bars; ⌥ mirrors the opposite side, ⇧ sets all sides. Flex/grid gap: drag the pink bars between children.
  • Alt shows distances to the parent and neighbours (or to the hovered element); drag a distance label to change that margin.
  • Smart guides & snapping to parent edges and padding box, siblings, viewport center and custom guides. Toggle with the magnet button or hold ⌘.
  • Rulers and custom guides: drag a guide out of a ruler, drag it back to remove it. Optional layout grid, outline mode and focus mode. None of this touches the page's code.
  • Floating contextual toolbar that follows the selection: text (font, size, weight, color, align), image (fit, position, radius, replace), container (auto layout, spacing, size, fill, radius), plus Align and ✨ AI. Popovers include a visual Auto Layout editor, a Grid editor (add/remove/resize columns and rows by dragging, gaps), a box-model Spacing editor, Size (Fixed / Hug / Fill) and Align & Distribute for multiple elements.
  • Add Text, Heading, Paragraph, Button, Image, Video, Container, Section or Divider (T, R, I): click where it should go; valid JSX/Vue/HTML is inserted and selected.
  • Double-click text to edit it inline (double-clicking a button edits its label). Text generated by code shows “This text is generated dynamically” with Open in Code instead of an editor.
  • Multi-selection → Arrange: align, equal spacing, equal width/height, Wrap in container (auto layout, row or column picked from the arrangement), Group, duplicate, delete, copy/paste design.
  • Copy design / Paste design (⌥⌘C / ⌥⌘V): typography, padding, margin, gap, colors, background, border, radius, shadow, opacity and layout settings — never text, images or component identity. Duplicate (⌘D), lock, hide temporarily (canvas only — Hide in code is a separate, explicit action), delete.
  • Command palette (⌘K) for every action. Keyboard: V select · P preview (use the site) · F focus · Esc clear selection · ↵ first child · ⇧↵ parent · Tab next sibling · arrows nudge (⇧ ×10).

Compact inspector (optional — open it from the toolbar’s ⋯ menu)

  • Grouped as Layout · Typography · Appearance · Effects · Responsive · Advanced, showing what matters for the selected kind of element. Advanced (collapsed) holds position, z-index, overflow, filters, blend modes, transforms, attributes, accessibility fields and custom CSS.
  • Constraints, inferred from the real layout: horizontal Left / Center / Right / Stretch, vertical Top / Center / Bottom / Stretch, sizing Fixed / Hug / Fill. Changing one writes the matching flex/grid/margin CSS for that layout — never absolute-positioning hacks.
  • Responsive lists the element’s per-breakpoint overrides (e.g. Mobile: w-full ml-0) with a Reset per breakpoint.
  • Component awareness: component name, file, props and instance count, with an unmistakable choice between Edit component (all instances, purple) and Edit this instance (green, written as a className on that usage).
  • Shows where styles are written (Writes to .card · styles.css, shared by 3), with This element only to keep a shared rule untouched.
  • Code mode shows the file, line, element and component, the mapping confidence, the current breakpoint, where styles are written, the source snippet, a Tailwind class editor grouped by breakpoint, and the last change (visual before → after plus the code diff), with Open in VS Code.

Responsive editing

  • Desktop (1440) / Tablet (768) / Mobile (375), a custom width, or drag the frame edges (snaps to device widths and breakpoints).

  • Breakpoint indicator on the top bar, frame and status bar. By default, edits on desktop change base styles and edits on tablet/mobile apply only to that breakpoint (max-md:, md:max-lg:, or media queries), so mobile tweaks never overwrite desktop. Choose All screens or Current breakpoint only explicitly at any time; another breakpoint is never changed silently.

  • Responsive check (⋯ menu): Desktop, Tablet and Mobile side by side, with detected problems — sideways scrolling, elements sticking out of the screen, clipped content, text that doesn’t wrap, buttons overflowing, cramped grids, heavy side padding and small tap targets. Click a problem to jump to that element at that width. Nothing is changed automatically.

Preview, compare and review

  • Before / After: Split slider, Overlay with opacity, or Original, synced with the page scroll.
  • Changes drawer: every change shows the element, action, time, file and breakpoint, the visual values (Width 144 → 168) and the code (w-36 → w-[168px]), with Diff, Open code, Revert (undo just this change, keeping later ones) and Revert to here. Turn on Review before writing to preview changes on the canvas first and apply them together (Visual changes → Preview → Apply / Cancel).
  • Sync status in the top bar: ✓ Synced · ● Preview · ↻ Applying · ⚠ Source changed · ✕ Error.
  • Edits made outside the editor (by hand in VS Code, git, a formatter) are detected for the files you’re working on: Source changed outside Visual Code Editor with Reload canvas, Review changes and Keep preview. They are never overwritten silently (undo of an older edit refuses if the file changed since).

AI assistant (✨ AI — optional; everything works without it)

  • Connect AI: Continue with ChatGPT, Continue with Claude, or (Advanced) Use API key. See AI providers.
  • The AI sees only the relevant context — the selection, its parent, siblings and children, their computed styles and layout, the source snippet, design tokens and the current breakpoint — never the whole repository.
  • Natural requests (“Make this section feel more premium”, “Make the cards more consistent”, “Give this button more breathing room”) plus quick tasks: layout fixes, responsive cleanup, typography, consistency, accessibility, and Explain this (plain-language explanation of how the element is built).
  • It returns structured changes only — element, property, old value → new value, reason — never free-form code. Proposals open with a live canvas preview and the exact diff: Apply all, Apply selected or Cancel.

Design suggestions & accessibility

  • Spots inconsistent spacing, radii, padding, widths, card heights, button heights, heading sizes, slight misalignment, elements wider than their container and heavy mobile padding around the selection, and offers a one-click fix that goes through the same review dialog. Nothing is applied automatically.
  • Accessibility: low text contrast (with a compliant color as the fix), images without alt text, buttons/links without a label, skipped heading levels.

Design tokens (⋯ menu)

  • Lists values repeated across the page (#0f172b used 16×, 24px used 23×). If a token already holds that value, Use token writes it for the selection (text-ink, var(--radius-card)); otherwise Create token adds it to your global stylesheet (@theme for Tailwind v4, :root otherwise) after you review the diff.

Source mapping

  • Every mapping shows 🟢 Exact, 🟡 Best match or 🔴 Uncertain. Structural changes (move, reorder, delete, duplicate, wrap) on an uncertain match ask for confirmation with the exact diff first.
  • Exact: Vite + React (the preview proxy patches React's jsx-dev-runtime so every host element carries file:line:col), React ≤ 18 _debugSource, and static HTML (served with per-element annotations).
  • Best match / Uncertain: Next.js (including Server Components via React 19 debug owners), Vue (__file of the owning component), and anything else. Elements are matched by component, tag, classes, text and attributes.
  • Open in Code jumps to the exact location and highlights the line.

Full inspector (every control scrubbable by dragging its label)

  • Typography with font picker (page, project, Google, system fonts), colors with HSV picker, eyedropper, recent/document colors and your Tailwind theme palette, gradients, background images, borders, radius, multiple shadows, effects, transforms and element attributes are all still available in the panel.

How styles are written

Project Default Example
Tailwind v3/v4 utility classes, edited in place py-24 → pt-18 pb-24, text-6xl → text-[52px]/none, max-md:w-full
CSS Modules the class's rule in the .module.css file .card { padding: 24px; }
styled-components / Emotion the component's template literal or css prop padding: 24px;
Plain CSS / Vue <style> / HTML <style> the matching rule, edited surgically (formatting kept) .hero { margin-top: 56px; }
Other inline style + generated stylesheet for breakpoints style={{ paddingTop: '16px' }}, .vce-1a2b3c { … }

Set visualCodeEditor.styleStrategy to force tailwind, inline or stylesheet.

Design tokens first. Values that match your theme are written as tokens: Tailwind scales and theme colors (text-violet-700, rounded-lg, p-section), and CSS custom properties (var(--radius-lg)) where your styles use them.

Class editing understands string literals, template literals, and cn() / clsx() / twMerge() calls. Shorthand families (p, px, pt, rounded-t, border-x…) are split and re-merged to the minimal set, and untouched classes keep their order.

Safe patches. Every visual action is one transaction: action → layout resolution → source patch → validation → preview → apply → history. The result is parsed before anything is written (JSX/TSX, Vue, HTML, CSS); a patch that would break a file is refused. Multi-file edits are applied atomically — if any file fails, every file is restored — recorded as one undo step, and can be dry-run to produce the diff you see before applying. Edits touch only the smallest region (formatting, comments and imports are preserved).

Settings

Setting Default Description
visualCodeEditor.devServerUrl "" Dev server URL. Empty = auto-detect running server, else start the dev script.
visualCodeEditor.devCommand "" Command to start the dev server (defaults to the dev/start script).
visualCodeEditor.styleStrategy auto auto, tailwind, inline, stylesheet.
visualCodeEditor.breakpoints { tablet: 768, desktop: 1024 } Breakpoints for responsive edits.
visualCodeEditor.saveAfterEdit true Save files after each edit so the dev server hot-reloads.
visualCodeEditor.ai.model claude-opus-5 Advanced: Claude model used with an Anthropic API key.
visualCodeEditor.ai.effort medium Advanced: effort level with an Anthropic API key (low … max).
visualCodeEditor.ai.openaiModel gpt-5 Advanced: model used with an OpenAI API key.
visualCodeEditor.ai.claudeModel / ai.codexModel "" Advanced: model passed to Claude Code / Codex (empty = their default for your plan).
visualCodeEditor.ai.claudePath / ai.codexPath "" Advanced: CLI locations if they aren’t found automatically.

AI providers

AI is optional and pluggable (src/ai/provider.ts): the editor only talks to an AI provider, which owns its own sign-in. Normal use never asks for a model, an endpoint or an API key.

Choice How it signs in Usage & billing
Continue with ChatGPT Your installed Codex CLI and its official Sign in with ChatGPT (codex login, opened in a VS Code terminal for you) Follows your ChatGPT plan’s Codex limits
Continue with Claude Your installed Claude Code and its official sign-in (claude auth login) Follows your Claude plan’s limits (Pro, Max, …)
Use API key (Advanced) Anthropic or OpenAI API key, stored only in VS Code Secret Storage Billed per use by the provider

How it works and what it never does:

  • A standalone extension can’t offer its own “Sign in with ChatGPT/Claude” — OpenAI and Anthropic don’t provide that to third-party extensions. Visual Code Editor therefore uses each vendor’s own official CLI in headless mode (codex exec, claude -p) with the account you signed into it. The extension never reads, stores or forwards ChatGPT/Claude credentials, cookies or tokens, and never uses undocumented endpoints.
  • Requests run in an empty temporary folder with tools disabled (Claude) or a read-only sandbox (Codex), so the AI can’t run commands or touch your project; structured output is enforced with a JSON schema.
  • API-key environment variables are removed for account requests, so a stray ANTHROPIC_API_KEY/OPENAI_API_KEY can’t silently switch you to paid API billing. If the CLI itself is signed in with an API key, the AI status says so.
  • When your plan’s limit is reached you see “Your AI plan usage limit has been reached” with View usage, Switch provider, Try again later and Use API key — the editor never switches providers or starts API billing on its own.
  • Credentials and keys stay in the extension host; the webview and the previewed website never receive them. Keys are never written to settings, project files, logs or browser storage.
  • Disconnect only stops this editor from using a provider; it doesn’t sign you out of Codex or Claude Code.

Commands

  • Visual Code Editor: Open Visual Editor (⌘⌥V)
  • Open Visual Editor at URL…
  • Start / Stop Dev Server
  • Undo / Redo Visual Edit
  • Connect AI (ChatGPT or Claude) / Disconnect AI
  • Use an API Key for AI (Advanced) / Remove Saved AI API Keys
  • Re-detect Project

Architecture

src/
  core/          VS Code-independent engine (unit tested)
    protocol.ts    messages between host ⇄ webview ⇄ page overlay
    jsx.ts         Babel-based JSX indexing + minimal text edits
    markup.ts      Vue SFC / HTML indexing + edits (@vue/compiler-dom)
    resolver.ts    DOM element → source element (exact + scored heuristics)
    tailwind.ts    CSS ⇄ Tailwind class engine (families, variants, v3/v4)
    styleEngine.ts tailwind / inline / stylesheet strategies
    session.ts     patch engine: transactions, atomic batches, rollback, dry-run diffs, history, revert-this, external-edit tracking
    validation.ts  parse-before-write checks for JSX/TSX, Vue, HTML and CSS
    cssEdit.ts     surgical CSS rule/declaration editing; cssTargets.ts picks CSS Modules / styled / Emotion / plain CSS
    snippets.ts    valid JSX/Vue/HTML for inserted elements; diff.ts unified diffs
    proxy.ts       preview proxy: overlay injection, HMR websockets, jsx-dev-runtime patch, static mode
    controller.ts  webview message handling shared by the extension and the dev harness
  overlay/       script injected into the previewed page: direct-manipulation canvas
                 (selection, handles, spacing/gap dragging, smart guides, measurements, suggestions)
  webview/       Preact editor UI (top bar, canvas + rulers, floating toolbar, properties, review, changes, AI)
  ai/            provider abstraction (provider.ts), Codex/ChatGPT (chatgpt.ts), Claude Code (claude.ts),
                 API keys (apiKey.ts), relevant-context building (context.ts), structured output (structuredOutput.ts)
  host/          VS Code integration (panel, sidebar, dev server terminal, AI sign-in and secret storage)

Development

npm install
npm run build        # bundles dist/extension.js, webview.js, overlay.js, harness.js
npm test             # unit tests for the core engine
npm run typecheck
npm run package      # produces visual-code-editor-<version>.vsix

Press F5 in VS Code to launch an Extension Development Host. To iterate on the UI in a normal browser, run the standalone harness against any project:

node dist/harness.js --root ./examples/vite-react --url http://localhost:5173
node dist/harness.js --root ./examples/static-site

The examples/ folder contains a React + Vite + Tailwind v4 landing page, a Vue + Vite app and a static HTML site.

Limitations

  • Text and classes that come from JavaScript expressions can't be edited visually. The inspector says so and offers Open in Code.
  • Elements rendered by .map() share a single source element, so editing one edits all of them (as in code). Deleting one deletes the whole list (map(() => null)).
  • Heuristic mappings (Next.js, Vue) show a confidence indicator. Verify low-confidence matches with Open in Code before structural edits.
  • Svelte and Astro are detected, but source editing currently targets JSX, Vue and HTML files.
  • Moving an element into another container works within one file (or into a component's usage site); cross-file moves are refused rather than guessed. Group / Wrap need elements that sit next to each other in the same container in source.
  • Continue with ChatGPT / Claude need the Codex CLI / Claude Code installed and signed in on this machine; availability and limits follow OpenAI’s and Anthropic’s plan rules.
  • The responsive check and design tokens look at the current page; Before/After compares style and text changes made in this session.
  • Before/After compares style and text changes made in the current session; structural changes (moves, inserts) show in the diff instead.
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft