# Monaco Editor — User Guide

Monaco Editor is the browser-based code editor that powers Visual Studio Code. The `monaco-editor` package is the **distributable build** of that editor: it bundles the editor core, syntax highlighting for ~90 languages, rich language services for TypeScript/JavaScript, CSS/SCSS/LESS, HTML, and JSON, plus the tooling you need to embed a full-featured code editor in any web page.

This guide is for **web developers who want to embed Monaco** in an application — a playground, an online IDE, a configuration editor, a documentation site, or anything that needs real code editing in the browser. It covers installation, the all-important web worker setup, creating and configuring editors, language support, themes, commands, and integration with every major bundler.

> [!NOTE]
> The actual editor engine ships as a sibling package called `monaco-editor-core`, which Microsoft builds from the [VS Code](https://github.com/microsoft/vscode) source tree at a pinned commit. The `monaco-editor` package wraps that core, adds the language definitions and language services, and is the package you install. Everywhere this guide says "Monaco", it means the editor you get from `npm install monaco-editor`.

---

## 1. Quick Start

The fastest way to see Monaco running is the prebuilt AMD bundle served from a CDN. Paste this into an HTML file and open it in a browser — no build step required.

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <style>
      html, body, #container { height: 100%; margin: 0; }
    </style>
  </head>
  <body>
    <div id="container"></div>

    <script src="https://cdn.jsdelivr.net/npm/monaco-editor/min/vs/loader.js"></script>
    <script>
      require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor/min/vs' } });
      require(['vs/editor/editor.main'], function () {
        monaco.editor.create(document.getElementById('container'), {
          value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
          language: 'javascript'
        });
      });
    </script>
  </body>
</html>
```

```text
A code editor with JavaScript syntax highlighting, a minimap, line numbers,
IntelliSense, and the full VS Code editing experience appears in #container.
```

> [!TIP]
> The CDN/AMD path is ideal for prototypes, demos, and plain HTML pages because the loader resolves the editor and its web workers for you. For production applications built with a bundler (webpack, Vite, esbuild, Parcel), use the ESM installation in the next section so the editor is part of your dependency graph and your assets are versioned.

The same hello-world with an ESM bundler:

```javascript
import * as monaco from 'monaco-editor';

monaco.editor.create(document.getElementById('container'), {
  value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
  language: 'javascript'
});
```

> [!IMPORTANT]
> With a bundler you **must** tell Monaco how to load its web workers, or language features will fail at runtime. See [Section 3: Web Workers](#3-web-workers-the-most-important-setup-step) before shipping. The CDN/AMD path handles this automatically; the ESM path does not.

---

## 2. Installation

### 2.1 Install from npm

```bash
npm install monaco-editor
```

```text
added 1 package
```

This installs the package whose `package.json` declares:

| Field | Value | Meaning |
|-------|-------|---------|
| `version` | `0.55.1` | The release you are using. |
| `main` | `./min/vs/editor/editor.main.js` | Minified AMD build (CommonJS `require`). |
| `module` | `./esm/vs/editor/editor.main.js` | ES module build (bundlers/`import`). |
| `typings` | `./esm/vs/editor/editor.main.d.ts` | TypeScript declarations. |

The `exports` map also exposes the ESM tree under subpaths, so deep imports such as `monaco-editor/esm/vs/editor/editor.api` and the per-language worker files resolve correctly.

### 2.2 What's in the package

After install, the relevant directories are:

| Path | Contents |
|------|----------|
| `monaco-editor/esm/` | ES module build — use this with bundlers. |
| `monaco-editor/min/` | Minified AMD build — use this with the CDN/AMD loader. |
| `monaco-editor/min/vs/loader.js` | The AMD loader for the CDN/AMD path. |
| `monaco-editor/esm/vs/editor/editor.main.js` | Full editor **with** all languages and features. |
| `monaco-editor/esm/vs/editor/editor.api.js` | Editor **API only** — you opt into languages/features yourself. |
| `monaco-editor/esm/vs/editor/editor.worker.js` | The core editor web worker. |
| `monaco-editor/esm/vs/language/{json,css,html,typescript}/*.worker.js` | Language-service web workers. |

> [!NOTE]
> `editor.main` pulls in **everything** (all languages + all editor features) and is the simplest starting point. `editor.api` pulls in **only** the editor and lets you import exactly the languages and features you want for a smaller bundle. Most applications start with `editor.main` and optimize later (see [Section 11](#11-shrinking-your-bundle)).

### 2.3 Three ways to import

Depending on your setup, you will import Monaco one of these ways:

=== "Bare specifier (bundler resolves it)"

    ```javascript
    import * as monaco from 'monaco-editor';
    ```

=== "Explicit ESM entry"

    ```javascript
    import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js';
    ```

=== "API-only (opt into languages/features)"

    ```javascript
    import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
    ```

---

## 3. Web Workers — the most important setup step

Monaco runs its expensive language work (TypeScript type-checking, JSON schema validation, CSS/HTML analysis, and the core editor's text-diffing/tokenization) inside **web workers** so the UI thread stays responsive. With a bundler, Monaco cannot guess the URLs of those worker scripts — **you must provide them** via the global `MonacoEnvironment` object.

> [!CAUTION]
> If you skip this step, you will see runtime errors such as `You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`, or language features (autocomplete, validation, formatting) will silently do nothing. This is the single most common Monaco integration problem.

### 3.1 The two hooks

`MonacoEnvironment` accepts **either** of two functions. Define one before you create any editor:

| Hook | Returns | Use when |
|------|---------|----------|
| `getWorker(moduleId, label)` | a `Worker` (or `Promise<Worker>`) | Your bundler can produce `Worker` instances directly (Vite, modern webpack 5, esbuild with a worker plugin). Preferred. |
| `getWorkerUrl(moduleId, label)` | a URL string to the worker script | Your bundler emits worker files to known URLs and you load them by path. |

The `label` argument tells you **which** worker is needed. Map each label to the matching worker bundle:

| `label` value | Worker to return |
|---------------|------------------|
| `json` | `json.worker` |
| `css`, `scss`, `less` | `css.worker` |
| `html`, `handlebars`, `razor` | `html.worker` |
| `typescript`, `javascript` | `ts.worker` |
| anything else (default) | `editor.worker` |

### 3.2 `getWorker` with Vite

Vite resolves the `?worker` suffix to a worker constructor, which is the cleanest approach:

```javascript
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';

self.MonacoEnvironment = {
  getWorker(_, label) {
    if (label === 'json') return new jsonWorker();
    if (label === 'css' || label === 'scss' || label === 'less') return new cssWorker();
    if (label === 'html' || label === 'handlebars' || label === 'razor') return new htmlWorker();
    if (label === 'typescript' || label === 'javascript') return new tsWorker();
    return new editorWorker();
  }
};
```

### 3.3 `getWorkerUrl` with webpack (manual)

If you wire workers by URL, return the path your bundler emits the worker to:

```javascript
import * as monaco from 'monaco-editor';

self.MonacoEnvironment = {
  getWorkerUrl: function (moduleId, label) {
    if (label === 'json') return './json.worker.bundle.js';
    if (label === 'css' || label === 'scss' || label === 'less') return './css.worker.bundle.js';
    if (label === 'html' || label === 'handlebars' || label === 'razor') return './html.worker.bundle.js';
    if (label === 'typescript' || label === 'javascript') return './ts.worker.bundle.js';
    return './editor.worker.bundle.js';
  }
};
```

> [!TIP]
> For webpack, you usually do **not** write this by hand — the official `monaco-editor-webpack-plugin` generates the `MonacoEnvironment` and emits the worker bundles for you. See [Section 10.1](#101-webpack--monaco-editor-webpack-plugin).

### 3.4 `getWorkerUrl` with esbuild

esbuild emits the worker files to a known output folder, so you return their relative URLs:

```javascript
import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js';

self.MonacoEnvironment = {
  getWorkerUrl: function (moduleId, label) {
    if (label === 'json') return './vs/language/json/json.worker.js';
    if (label === 'css' || label === 'scss' || label === 'less') return './vs/language/css/css.worker.js';
    if (label === 'html' || label === 'handlebars' || label === 'razor') return './vs/language/html/html.worker.js';
    if (label === 'typescript' || label === 'javascript') return './vs/language/typescript/ts.worker.js';
    return './vs/editor/editor.worker.js';
  }
};
```

### 3.5 `getWorkerUrl` with Parcel

Parcel's `url:` import scheme gives you the emitted URL of each worker:

```javascript
import JSONWorker from 'url:monaco-editor/esm/vs/language/json/json.worker.js';
import CSSWorker from 'url:monaco-editor/esm/vs/language/css/css.worker.js';
import HTMLWorker from 'url:monaco-editor/esm/vs/language/html/html.worker.js';
import TSWorker from 'url:monaco-editor/esm/vs/language/typescript/ts.worker.js';
import EditorWorker from 'url:monaco-editor/esm/vs/editor/editor.worker.js';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js';

self.MonacoEnvironment = {
  getWorkerUrl: function (moduleId, label) {
    if (label === 'json') return JSONWorker;
    if (label === 'css' || label === 'scss' || label === 'less') return CSSWorker;
    if (label === 'html' || label === 'handlebars' || label === 'razor') return HTMLWorker;
    if (label === 'typescript' || label === 'javascript') return TSWorker;
    return EditorWorker;
  }
};
```

> [!NOTE]
> Returning **only** the editor worker (the `default` branch) is valid if you don't need any rich language services. A minimal setup that returns `editor.worker` for every label still gives you syntax highlighting via the basic-language tokenizers — you just lose TypeScript/JSON/CSS/HTML IntelliSense and validation.

### 3.6 Cross-origin workers

If your worker files are served from a different origin than the page (for example a CDN), browsers block constructing a `Worker` directly from the cross-origin URL. The standard workaround is to wrap the real worker in a same-origin proxy script created from a Blob:

```javascript
self.MonacoEnvironment = {
  getWorkerUrl: function (moduleId, label) {
    const workerUrl = '/* …resolve to the cross-origin URL… */';
    const proxy = URL.createObjectURL(
      new Blob([`importScripts('${workerUrl}');`], { type: 'application/javascript' })
    );
    return proxy;
  }
};
```

> [!TIP]
> The `monaco-editor-webpack-plugin` already generates this Blob-proxy logic for cross-origin worker URLs automatically. If you use the plugin, set its `publicPath` option and let it handle the cross-origin case.

---

## 4. Creating and disposing an editor

### 4.1 `monaco.editor.create`

`monaco.editor.create(domElement, options)` mounts an editor into a DOM element and returns an editor instance:

```javascript
const editor = monaco.editor.create(document.getElementById('container'), {
  value: 'const foo = () => 0;',
  language: 'javascript',
  theme: 'vs-dark'
});
```

```text
The editor fills #container and renders the code with dark-theme highlighting.
```

> [!IMPORTANT]
> The container element must have a height. Monaco sizes itself to its container; if the container collapses to `0px`, the editor renders but is invisible. Give the container an explicit height (CSS `height`, flex, or grid) or enable `automaticLayout` (Section 5) so the editor re-measures on resize.

### 4.2 Disposing

Editors hold DOM nodes, listeners, and worker connections. When you remove an editor, dispose it to release them:

```javascript
editor.dispose();
```

If you created models explicitly (Section 6), dispose those too:

```javascript
const model = editor.getModel();
editor.setModel(null);
if (model) model.dispose();
```

> [!WARNING]
> Failing to dispose editors and models in single-page apps that mount/unmount editors repeatedly leads to leaked workers and detached DOM nodes. Always dispose on component teardown (e.g. React `useEffect` cleanup, Vue `onUnmounted`).

---

## 5. Editor options

You pass options when creating the editor and change them later with `editor.updateOptions(...)`. These are the most commonly used options, all confirmed against the editor's own option surface:

| Option | Type | Example | Effect |
|--------|------|---------|--------|
| `value` | `string` | `'hello'` | Initial text (when not using an explicit model). |
| `language` | `string` | `'typescript'` | Language id for syntax highlighting + services. |
| `theme` | `string` | `'vs-dark'` | Color theme (see [Section 7](#7-themes)). |
| `model` | `ITextModel \| null` | a created model | Use a specific model instead of `value`/`language`. |
| `readOnly` | `boolean` | `true` | Disable editing. |
| `lineNumbers` | `'on' \| 'off' \| 'relative' \| fn` | `'on'` | Line-number gutter mode. |
| `glyphMargin` | `boolean` | `true` | Show the glyph margin (for decorations/breakpoints). |
| `minimap` | `{ enabled: boolean }` | `{ enabled: false }` | Toggle the minimap. |
| `roundedSelection` | `boolean` | `false` | Rounded vs. square selection corners. |
| `scrollBeyondLastLine` | `boolean` | `false` | Allow scrolling past the last line. |
| `renderWhitespace` | `'none' \| 'boundary' \| 'all'` | `'all'` | Render whitespace characters. |
| `wordWrap` | `'off' \| 'on' \| 'wordWrapColumn' \| 'bounded'` | `'on'` | Soft wrapping. |
| `folding` | `boolean` | `true` | Enable code folding. |
| `automaticLayout` | `boolean` | `true` | Re-layout automatically when the container resizes. |

> [!NOTE]
> The full option set is large (hundreds of options covering cursor, scrollbar, suggestions, bracket pair colorization, sticky scroll, accessibility, and more). The above are the everyday options. For the exhaustive, version-accurate list, consult the API reference — see [Section 14: Reference](#14-reference).

### 5.1 Changing options at runtime

```javascript
editor.updateOptions({ lineNumbers: 'off' });
editor.updateOptions({ minimap: { enabled: true } });
editor.updateOptions({ wordWrap: 'on' });
editor.updateOptions({ readOnly: true });
```

```text
Each call applies immediately without recreating the editor.
```

### 5.2 Reading and writing content

```javascript
const text = editor.getValue();        // current text
editor.setValue('new content');        // replace all text
const position = editor.getPosition(); // { lineNumber, column }
editor.setScrollTop(0);                // scroll to top
```

---

## 6. Models — the text behind the editor

A **model** holds the text, language, and edit history for a document. The editor is a *view* onto a model. Working with models explicitly lets you share one document across editors, attach a file URI (which TypeScript and JSON services use to resolve modules and schemas), and manage multiple open documents.

### 6.1 Creating a model

```javascript
const model = monaco.editor.createModel(
  'class Test {}',
  'typescript',
  monaco.Uri.parse('file:///main.ts')
);

const editor = monaco.editor.create(document.getElementById('root'), {
  model: model,
  theme: 'vs-dark'
});
```

> [!TIP]
> The third argument — the model **URI** — matters for the TypeScript/JavaScript language service. Giving models real `file:///` URIs lets the service treat them as a project, resolve imports between them, and report cross-file diagnostics.

### 6.2 Switching models

```javascript
const oldModel = editor.getModel();
const newModel = monaco.editor.createModel(source, 'python');
editor.setModel(newModel);
if (oldModel) oldModel.dispose();
```

### 6.3 Changing a model's language

```javascript
monaco.editor.setModelLanguage(model, 'json');
```

### 6.4 Reacting to edits

```javascript
model.onDidChangeContent((event) => {
  console.log('document changed', model.getValue());
});
```

---

## 7. Themes

Monaco ships four built-in themes:

| Theme id | Description |
|----------|-------------|
| `vs` | Light (default). |
| `vs-dark` | Dark. |
| `hc-black` | High-contrast dark. |
| `hc-light` | High-contrast light. |

Set the theme at creation time (`theme:` option) or switch it globally at any time:

```javascript
monaco.editor.setTheme('vs');
monaco.editor.setTheme('vs-dark');
monaco.editor.setTheme('hc-black');
```

> [!IMPORTANT]
> `monaco.editor.setTheme` is **global** — it changes the theme for every editor on the page, not just one instance.

### 7.1 Custom themes

Define your own theme with token color rules and editor colors, then apply it by name:

```javascript
monaco.editor.defineTheme('myTheme', {
  base: 'vs-dark',
  inherit: true,
  rules: [
    { token: 'comment', foreground: '6A9955', fontStyle: 'italic' },
    { token: 'keyword', foreground: 'C586C0' }
  ],
  colors: {
    'editor.background': '#1E1E1E'
  }
});

monaco.editor.setTheme('myTheme');
```

---

## 8. Language support

Monaco's language support comes in two tiers.

### 8.1 Basic languages (syntax highlighting)

The `monaco-editor` package bundles **Monarch** tokenizer definitions that provide syntax highlighting, bracket matching, comment toggling, and auto-indentation for a large catalog of languages. When you import `editor.main`, every basic language is registered automatically. The full set bundled in this release:

```text
abap, apex, azcli, bat, bicep, cameligo, clojure, coffee, cpp, csharp, csp,
css, cypher, dart, dockerfile, ecl, elixir, flow9, freemarker2, fsharp, go,
graphql, handlebars, hcl, html, ini, java, javascript, julia, kotlin, less,
lexon, liquid, lua, m3, markdown, mdx, mips, msdax, mysql, objective-c,
pascal, pascaligo, perl, pgsql, php, pla, postiats, powerquery, powershell,
protobuf, pug, python, qsharp, r, razor, redis, redshift, restructuredtext,
ruby, rust, sb, scala, scheme, scss, shell, solidity, sophia, sparql, sql,
st, swift, systemverilog, tcl, twig, typescript, typespec, vb, wgsl, xml, yaml
```

> [!NOTE]
> Basic-language support is highlighting only — it does **not** require a web worker and does **not** provide IntelliSense, validation, or formatting. For those, you need a rich language service (next section).

List the registered languages at runtime:

```javascript
monaco.languages.getLanguages().forEach((language) => {
  console.log(language.id);
});
```

Register a language id (for example to attach your own tokenizer):

```javascript
monaco.languages.register({ id: 'mylang' });
```

### 8.2 Rich language services

Four languages get full **language services** running in web workers: TypeScript/JavaScript, JSON, CSS/SCSS/LESS, and HTML/Handlebars/Razor. These provide completions, hover, diagnostics, formatting, and more. They are exposed under `monaco.languages.<name>` and are configured through a `*Defaults` object.

> [!CAUTION]
> Rich language services require the matching web worker (Section 3). If you only wired up `editor.worker`, TypeScript completions and JSON validation will not appear.

#### TypeScript / JavaScript

```javascript
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
  target: monaco.languages.typescript.ScriptTarget.ES2020,
  module: monaco.languages.typescript.ModuleKind.ESNext,
  strict: true
});

monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
  noSemanticValidation: false,
  noSyntaxValidation: false
});

monaco.languages.typescript.typescriptDefaults.setInlayHintsOptions({
  includeInlayParameterNameHints: 'all',
  includeInlayFunctionParameterTypeHints: true,
  includeInlayVariableTypeHints: true,
  includeInlayFunctionLikeReturnTypeHints: true,
  includeInlayEnumMemberValueHints: true
});
```

Add extra type declarations (e.g. library `.d.ts`) so completions know about your APIs:

```javascript
monaco.languages.typescript.typescriptDefaults.addExtraLib(
  'declare function greet(name: string): void;',
  'file:///globals.d.ts'
);
```

> [!TIP]
> Use `javascriptDefaults` (instead of `typescriptDefaults`) to configure the service for plain JavaScript models. Both share the same option shapes.

#### JSON

```javascript
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
  validate: true,
  schemas: [
    {
      uri: 'http://myserver/schema.json',
      fileMatch: ['*'],
      schema: {
        type: 'object',
        properties: { name: { type: 'string' } },
        required: ['name']
      }
    }
  ]
});
```

```text
Editing a JSON model now shows live validation errors and schema-driven completions.
```

#### CSS / SCSS / LESS and HTML

```javascript
monaco.languages.css.cssDefaults.setOptions({
  validate: true,
  lint: { emptyRules: 'warning' }
});

monaco.languages.html.htmlDefaults.setOptions({
  format: { wrapLineLength: 120 }
});
```

> [!NOTE]
> CSS support covers three languages handled by one worker (`css`, `scss`, `less`); HTML support covers `html`, `handlebars`, and `razor`. The defaults objects are `cssDefaults`/`scssDefaults`/`lessDefaults` and `htmlDefaults`/`handlebarDefaults`/`razorDefaults` respectively.

### 8.3 Extending a language yourself

For languages without a rich service, you can register your own providers — completions, hovers, definitions, formatting, and so on:

```javascript
monaco.languages.registerCompletionItemProvider('mylang', {
  provideCompletionItems: () => ({
    suggestions: [
      {
        label: 'hello',
        kind: monaco.languages.CompletionItemKind.Keyword,
        insertText: 'hello'
      }
    ]
  })
});
```

> [!TIP]
> The official Monaco **Playground** (linked in [Section 14](#14-reference)) has runnable, copy-paste examples for every provider type — completion, hover, signature help, code lens, color, folding, semantic tokens, inlay hints, symbols, and custom Monarch languages. It is the best place to learn the provider APIs.

---

## 9. Commands, actions, and keybindings

### 9.1 Add a command

A **command** binds a keyboard shortcut to a handler:

```javascript
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.F9, function () {
  alert('Command Running!!');
});
```

### 9.2 Add an action

An **action** is a richer command that also appears in the command palette and (optionally) the right-click context menu:

```javascript
editor.addAction({
  id: 'my-unique-id',
  label: 'My Label!!!',
  keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.F10],
  contextMenuGroupId: 'navigation',
  contextMenuOrder: 2.5,
  run: function (ed) {
    console.log("i'm running => " + ed.getPosition());
  }
});
```

```text
The action is now reachable via Ctrl/Cmd+F10, the F1 command palette
("My Label!!!"), and the editor's right-click context menu.
```

### 9.3 Building keybindings

Combine modifiers and keys with bitwise OR using `monaco.KeyMod` and `monaco.KeyCode`:

| Constant | Example |
|----------|---------|
| `monaco.KeyMod.CtrlCmd` | Ctrl on Windows/Linux, Cmd on macOS |
| `monaco.KeyMod.Shift` | Shift |
| `monaco.KeyMod.Alt` | Alt/Option |
| `monaco.KeyMod.WinCtrl` | Ctrl on macOS, Win on Windows |
| `monaco.KeyCode.KeyS`, `monaco.KeyCode.F9`, … | Letter and function keys |

```javascript
// Ctrl/Cmd + Shift + S
const chord = monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyS;
```

---

## 10. Bundler integration recipes

Monaco ships sample projects for every major bundler. The patterns below are distilled from those samples.

### 10.1 Webpack — `monaco-editor-webpack-plugin`

The official plugin generates the `MonacoEnvironment` worker wiring and emits the worker bundles, so you don't hand-write Section 3:

```bash
npm install monaco-editor monaco-editor-webpack-plugin
```

```javascript
// webpack.config.js
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');

module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader', 'css-loader'] },
      { test: /\.ttf$/, type: 'asset/resource' }
    ]
  },
  plugins: [new MonacoWebpackPlugin()]
};
```

```javascript
// app.js
import * as monaco from 'monaco-editor';
monaco.editor.create(document.getElementById('container'), {
  value: 'hello world',
  language: 'plaintext'
});
```

Restrict the bundle to only the languages and features you use:

```javascript
new MonacoWebpackPlugin({
  languages: ['javascript', 'typescript', 'json'],
  features: ['!gotoSymbol']   // include all features except gotoSymbol
});
```

> [!TIP]
> In the plugin's `features` list, prefix a feature with `!` to **exclude** it while keeping all others. The plugin's full option set (`languages`, `customLanguages`, `features`, `filename`, `monacoEditorPath`, `publicPath`, `globalAPI`) is documented in the Admin Guide.

### 10.2 Vite

Use the `getWorker` setup from [Section 3.2](#32-getworker-with-vite). No plugin is required. A typical React component:

```tsx
import { useEffect, useRef } from 'react';
import * as monaco from 'monaco-editor';
import './userWorker'; // file that sets self.MonacoEnvironment (Section 3.2)

export function Editor() {
  const ref = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const editor = monaco.editor.create(ref.current!, {
      value: 'console.log("hello")',
      language: 'javascript',
      theme: 'vs-dark'
    });
    return () => editor.dispose();
  }, []);
  return <div ref={ref} style={{ height: '100%' }} />;
}
```

### 10.3 esbuild

Use the `getWorkerUrl` setup from [Section 3.4](#34-getworkerurl-with-esbuild) and copy the worker files into your output directory as part of the build. The bundled sample uses a small `build.js` that runs esbuild and stages the `vs/` worker tree alongside the app.

### 10.4 Parcel

Use the `url:` worker imports from [Section 3.5](#35-getworkerurl-with-parcel). Parcel resolves and emits each worker automatically.

### 10.5 Electron

Electron renderer processes are browser contexts, so the standard ESM + worker setup applies. Load the bundled page into a `BrowserWindow`:

```javascript
const { app, BrowserWindow } = require('electron');

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: { worldSafeExecuteJavaScript: true }
  });
  win.loadURL(`file://${__dirname}/dist/index.html`);
}

app.on('ready', createWindow);
```

> [!NOTE]
> The repository also contains **legacy AMD** samples for Electron and NW.js under `samples/legacy/`. Those are no longer supported and are slated for removal — prefer the ESM samples for any new project.

---

## 11. Shrinking your bundle

The full `editor.main` import includes every language and editor feature. To trim it:

- **Use the webpack plugin's `languages`/`features` options** (Section 10.1) — the easiest path for webpack users.
- **Import `editor.api` and opt in manually.** Start from `monaco-editor/esm/vs/editor/editor.api.js`, then import only the feature and language contributions you need. The bundled `browser-esm-webpack-small` sample shows the pattern: a commented list of every available feature import (e.g. `.../contrib/find/browser/findController.js`) and language contribution (e.g. `.../basic-languages/python/python.contribution.js`) that you uncomment selectively.

```javascript
// Opt-in example: editor + find + Python highlighting only
import 'monaco-editor/esm/vs/editor/browser/controller/coreCommands.js';
import 'monaco-editor/esm/vs/editor/contrib/find/browser/findController.js';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
import 'monaco-editor/esm/vs/basic-languages/python/python.contribution.js';

self.MonacoEnvironment = {
  getWorkerUrl: () => './editor.worker.bundle.js'
};

monaco.editor.create(document.getElementById('container'), {
  value: 'print("hello")',
  language: 'python'
});
```

> [!TIP]
> Opting in manually is the most effective way to reduce bundle size, but it is also the most error-prone — miss a feature import and that feature silently disappears. Start with `editor.main`, ship, then optimize with measurements.

---

## 12. Diff editor

To compare two documents side by side, create a **diff editor** with an original and a modified model:

```javascript
const original = monaco.editor.createModel('line one\nline two', 'text/plain');
const modified = monaco.editor.createModel('line one\nline 2', 'text/plain');

const diffEditor = monaco.editor.createDiffEditor(document.getElementById('container'), {
  theme: 'vs-dark',
  renderSideBySide: true
});

diffEditor.setModel({ original, modified });
```

```text
A two-pane diff highlighting the change from "line two" to "line 2".
```

> [!NOTE]
> Set `renderSideBySide: false` for an inline (unified) diff. Dispose the diff editor and both models when you're done.

---

## 13. Troubleshooting

### Error: `You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`

- **Cause:** No web worker provider was configured, and a feature tried to start a worker.
- **Solution:** Set `self.MonacoEnvironment` with either `getWorker` or `getWorkerUrl` **before** creating any editor (Section 3).
- **Prevention:** Put the worker setup in a module that is imported first, or use `monaco-editor-webpack-plugin` so it's generated for you.

### Language features (autocomplete/validation) do nothing

- **Cause:** Only the core `editor.worker` is wired; the language-specific worker (e.g. `ts.worker`, `json.worker`) is missing.
- **Solution:** Map each `label` (`json`, `css`, `html`, `typescript`/`javascript`) to its worker in `getWorker`/`getWorkerUrl` (Section 3.1).
- **Prevention:** Use the full mapping from the samples, even if you think you only need one language.

### The editor is invisible / zero height

- **Cause:** The container element has no height.
- **Solution:** Give the container an explicit `height`, or set `automaticLayout: true` so the editor re-measures.
- **Prevention:** Style the container (`height: 100%` within a sized parent) before creating the editor.

### Editor doesn't resize when its container changes

- **Cause:** Monaco measures once at creation.
- **Solution:** Enable `automaticLayout: true`, or call `editor.layout()` after the container resizes.

### Language namespaces are missing after importing `editor.api.js` (0.55.0+)

- **Cause:** As of `0.55.0` the language namespaces (e.g. `monaco.languages.typescript`) are no longer attached when importing the API-only entry `editor.api.js`; they were moved. (See issue [#5346](https://github.com/microsoft/monaco-editor/issues/5346).)
- **Solution:** Import `editor.main` (which registers languages), or explicitly import the language contributions you need (Section 11).
- **Prevention:** Use `editor.main` unless you are deliberately doing a minimal opt-in build.

### Error: `monaco is not loaded yet`

- **Cause:** Code referenced the global `monaco` before the AMD loader finished resolving `vs/editor/editor.main`.
- **Solution:** Put all editor code **inside** the `require(['vs/editor/editor.main'], …)` callback (Section 1).

### `Failed to load source map: simpleWorker.nls.js.map`

- **Cause:** A worker source map referenced in the shipped files isn't served. (See issue [#3336](https://github.com/microsoft/monaco-editor/issues/3336).)
- **Solution:** This is a dev-tools console warning, not a functional error — it does not affect the editor. Disable source-map fetching in dev tools or ignore it.

### Worker NLS file has a doubled extension (`nls.messages.<lang>.js.js`)

- **Cause:** A packaging bug in some `0.55.x` builds produces a `.js.js` suffix for localized NLS message files. (See issue [#5345](https://github.com/microsoft/monaco-editor/issues/5345).)
- **Solution:** If you load localized messages, verify the emitted filename and adjust your copy step; track the linked issue for a fixed release.

### Right-click "Paste" does nothing

- **Cause:** Browsers restrict programmatic clipboard reads; the context-menu paste cannot access the system clipboard without a user gesture/permission. (See issue [#5158](https://github.com/microsoft/monaco-editor/issues/5158).)
- **Solution:** Use the keyboard shortcut (Ctrl/Cmd+V), which the browser permits.

### Content Security Policy blocks the editor or workers

- **Cause:** Monaco creates workers (and, for cross-origin workers, Blob URLs) and injects styles. A strict CSP can block these.
- **Solution:** Allow `worker-src blob:` (and `script-src blob:` if you use the cross-origin Blob proxy) and the worker origins. If you use Trusted Types, provide a `MonacoEnvironment.createTrustedTypesPolicy` (see the Admin Guide's security section).

---

## 14. FAQ

**Q: What's the difference between `monaco-editor` and `monaco-editor-core`?**
`monaco-editor-core` is the editor engine, built from the VS Code source. `monaco-editor` is what you install — it bundles the core plus all the language definitions and language services. Use `monaco-editor`.

**Q: Do I need a server?**
No. Monaco is entirely client-side. The "workers" are browser web workers, not server processes.

**Q: Why are there so many `.worker.js` files?**
Each rich language service (TypeScript, JSON, CSS, HTML) runs in its own web worker so heavy analysis doesn't block the UI. The core editor has one worker too. You wire them up in `MonacoEnvironment` (Section 3).

**Q: Can I use Monaco without any workers?**
Yes, with reduced functionality. Return the core `editor.worker` for every label and you get syntax highlighting and editing, but no TypeScript/JSON/CSS/HTML IntelliSense or validation.

**Q: How do I get TypeScript autocompletion for my own libraries?**
Call `monaco.languages.typescript.typescriptDefaults.addExtraLib(declarationSource, uri)` with your `.d.ts` content (Section 8.2).

**Q: How do I make the editor read-only?**
Pass `readOnly: true` at creation or call `editor.updateOptions({ readOnly: true })`.

**Q: How do I change the theme for just one editor?**
You can't — `monaco.editor.setTheme` is global. To show different color schemes, render editors on separate pages/iframes, or switch the global theme when focus changes.

**Q: Which languages have full IntelliSense vs. just highlighting?**
Full language services: TypeScript/JavaScript, JSON, CSS/SCSS/LESS, HTML/Handlebars/Razor. All other bundled languages get highlighting (Monarch) only.

**Q: How do I support a language that isn't bundled?**
Register it with `monaco.languages.register({ id })` and provide a Monarch tokenizer via `monaco.languages.setMonarchTokensProvider`, plus any providers you need. See the Playground's "custom languages" example.

**Q: Is Monaco mobile/touch friendly?**
Monaco targets desktop browsers. There is an `iPadShowKeyboard` helper and basic touch support, but the editor is optimized for keyboard-and-mouse use.

**Q: How do I update to a new version?**
Bump `monaco-editor` in your `package.json` and re-bundle. Watch the changelog for breaking changes — the `0.55.0` language-namespace move (issue #5346) is an example of a change that affected API-only imports.

**Q: Where is the official live editor to experiment in?**
The Monaco Playground (see Reference below) lets you run and tweak every example in the browser.

---

## 15. Reference

### Import-path cheat sheet

| What | ESM path |
|------|----------|
| Full editor (all languages/features) | `monaco-editor` or `monaco-editor/esm/vs/editor/editor.main.js` |
| Editor API only | `monaco-editor/esm/vs/editor/editor.api` |
| Core editor worker | `monaco-editor/esm/vs/editor/editor.worker.js` |
| JSON worker | `monaco-editor/esm/vs/language/json/json.worker.js` |
| CSS worker | `monaco-editor/esm/vs/language/css/css.worker.js` |
| HTML worker | `monaco-editor/esm/vs/language/html/html.worker.js` |
| TypeScript/JS worker | `monaco-editor/esm/vs/language/typescript/ts.worker.js` |

### Worker label map

| `label` | Worker |
|---------|--------|
| `json` | json worker |
| `css` / `scss` / `less` | css worker |
| `html` / `handlebars` / `razor` | html worker |
| `typescript` / `javascript` | ts worker |
| (default) | editor worker |

### Built-in themes

`vs` · `vs-dark` · `hc-black` · `hc-light`

### Key API entry points

| Call | Purpose |
|------|---------|
| `monaco.editor.create(el, opts)` | Create an editor. |
| `monaco.editor.createDiffEditor(el, opts)` | Create a diff editor. |
| `monaco.editor.createModel(value, lang, uri?)` | Create a text model. |
| `monaco.editor.setTheme(name)` | Set the global theme. |
| `monaco.editor.defineTheme(name, data)` | Define a custom theme. |
| `monaco.editor.setModelLanguage(model, lang)` | Change a model's language. |
| `monaco.languages.register({ id })` | Register a language id. |
| `monaco.languages.getLanguages()` | List registered languages. |
| `monaco.languages.typescript.typescriptDefaults` | Configure the TS service. |
| `monaco.languages.json.jsonDefaults` | Configure the JSON service. |
| `monaco.languages.css.cssDefaults` | Configure the CSS service. |
| `monaco.languages.html.htmlDefaults` | Configure the HTML service. |
| `editor.addCommand(keybinding, handler)` | Bind a keyboard command. |
| `editor.addAction(descriptor)` | Add a palette/context-menu action. |
| `editor.updateOptions(opts)` | Change editor options. |
| `editor.dispose()` | Release the editor. |

### Official resources

- **Playground (runnable examples):** https://microsoft.github.io/monaco-editor/playground.html
- **API reference (typedoc):** https://microsoft.github.io/monaco-editor/typedoc/index.html
- **Website & docs:** https://microsoft.github.io/monaco-editor/
- **Source & issues:** https://github.com/microsoft/monaco-editor

> [!NOTE]
> The exhaustive list of editor options, model APIs, and provider interfaces is generated from the TypeScript declarations and published in the typedoc API reference. When you need an option or method this guide doesn't cover, that reference is the authoritative source for your installed version.

---

_Generated June 2026 from microsoft/monaco-editor at 4cd0f4f. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
