Monaco HTML editor: connect the source model, language support, and saved value

To edit HTML with Monaco, create a text model with the html language, attach it to an editor in a container with a real height, and configure the workers for your bundler. Monaco edits source text. It does not automatically render that HTML as a webpage or save it to your application. Monaco ESM integration

An embedded contact-page editor is a useful example. Its author changes “Email the support desk” to “Email the accessibility support desk.” The source editor, any optional rendered preview, and the saved record each need to contain the new wording. A colored <h1> token proves only that part of the editing interface is active.

Give the editor somewhere visible to render

The host page needs a container with dimensions:

<div id="notice-source" style="height: 360px; border: 1px solid #bbc8c3"></div>

In a browser application where the Monaco package, its CSS, and bundler-specific worker setup are already configured, create one model and one editor:

import * as monaco from 'monaco-editor';

const model = monaco.editor.createModel(
  '<h1>Contact support</h1>\n<p>Email the support desk.</p>',
  'html',
  monaco.Uri.parse('inmemory://support/contact.html')
);

const editor = monaco.editor.create(
  document.getElementById('notice-source'),
  {
    model,
    automaticLayout: true,
    wordWrap: 'on',
    minimap: { enabled: false }
  }
);

This is application source for a configured build, not a script that a browser can load directly from an unprocessed HTML file. The model creation API accepts the initial value, language, and optional URI. Give different open documents different model URIs; do not reuse this example's URI for every tab.

If the editor looks blank, inspect the container's actual dimensions before changing language configuration. A hidden panel can also need layout attention when shown. automaticLayout observes container changes, but the surrounding application still needs to give that container usable space. Editor construction options

Diagnose language support separately from syntax colors

If HTML text colors appear but suggestions do not work, inspect the build's HTML language support and worker loading. Monaco's official integration guide shows separate worker routes for HTML, CSS, JSON, and JavaScript/TypeScript. The HTML route also handles labels such as Handlebars and Razor in those examples.

Use the integration pattern for the bundler you actually run. Webpack worker filenames and Vite worker imports are not interchangeable copy-and-paste settings. Keep the Monaco package and worker assets from the same installed version. In the development browser, check the Console and Network panels when invoking suggestions inside a tag; a worker URL returning a 404 or the application's HTML fallback is a different failure from an empty editor container.

Use a small acceptance check: type < in the HTML model and request suggestions with the editor's suggestion command or keyboard shortcut. Then type an ordinary HTML element and inspect the available attributes. Record what your configured build actually offers. Do not treat a successful token color change as proof that the language service loaded.

Microsoft describes Monaco's models and providers in the project documentation. Full VS Code extension behavior is not implied by embedding its editor component; choose the language features your application needs.

Read the model at the actual save action

Once the author has edited the contact page, capture its current source:

const currentHtml = model.getValue();
// Pass currentHtml to the application's existing save operation.

getValue() reads the current model. It does not submit a request, establish that the server accepted it, or update an earlier string captured at initialization. Save the value obtained at the user's Save action and preserve an unsaved state if that request fails. Text model API

For the fictional contact page, inspect the outgoing value and reopen the same saved record. Both should contain “accessibility support desk.” If a rendered preview still shows the old wording, inspect its update path separately. Keep any preview of untrusted HTML within the application's intended security boundary instead of inserting it into the surrounding editor page.

Release the document when its owner closes it

For this example, the code that creates the standalone model owns its lifetime. When that document is permanently closed, after resolving any unsaved changes:

editor.dispose();
model.dispose();

A model shared by several views needs a shared ownership policy; one closing view should not dispose it while another still uses it. Open the contact page, close it, and reopen it in your own application to check that the source, model identity, and controls remain coherent.

The VS Code HTML scaffold guide addresses authoring a local file in a desktop editor. In an embedded Monaco application, finish by checking the current model, successful persistence, and any reader preview as separate results.

Keep reading