Library / SDK
suren-atoyan/monaco-react avatar
suren-atoyan/monaco-react

Monaco inside React without a bundler plugin: what @monaco-editor/react loads and what it leaves to you

Monaco Editor for React - use the monaco-editor in any React application without needing to use webpack (or rollup/parcel/etc) configuration files / plugins

4,749 stars320 forksTypeScriptMIT

At a glance

What is it?
A wrapper that loads the VS Code based editor through the loader instead of a webpack or Vite plugin, handing you components, a hook and a loader utility. It saves the bundler step and hands you the editor peer dependency, a release candidate version line, and environment notes you still have to read.
Who is it for?
Use it when you want a VS Code class editor in a React app and would rather not write bundler plugin configuration, and check the monaco-editor peer version plus the release candidate status of the 4.8 line before you pin anything. Leave it alone if your build already loads monaco-editor by hand, if you cannot add the peer package, or if you need a stable tag rather than an rc, since React 19 support sits on the @next tag.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 168 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One import line replaces the bundler plugin

The monaco-editor package is the browser code editor that also powers VS Code, and shipping it inside an app normally means writing bundler glue or adding a plugin for whichever toolchain you happen to run. This wrapper takes over that setup step and hands you React components instead. The entry surface is a default export plus three named exports, so a single import line gets you the editor, the diff view, the loader utility and the hook that returns the loaded monaco namespace:

javascript
import Editor, { DiffEditor, useMonaco, loader } from '@monaco-editor/react';

The stated goal is using monaco-editor in any React application without needing webpack, or rollup, or parcel, configuration files and plugins. Apps generated by create-react-app, create-snowpack-app, vite and Next.js are named as supported, and none of them has to be ejected or rewired. The loader is what makes that possible, and the feature list calls out that it is already integrated with @monaco-editor/loader, which is also the one runtime dependency in the manifest.

npm install leaves the editor peer dependency to you

Installation is a single package name, and the install command itself carries a caveat about which tag to ask for:

bash
npm install @monaco-editor/react # or @monaco-editor/react@next for React v19
bash
yarn add @monaco-editor/react

The editor itself is not a dependency. monaco-editor sits in peerDependencies with the range `>= 0.25.0 < 1`, and there is a note that the TypeScript type definitions come from the monaco-editor package, so an app without it installed gets no types and possibly no editor. An existing dependency outside that window turns into a peer conflict at install time rather than a build error pointing at the wrapper. react and react-dom accept `^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0`, so hooks-era React is the floor. A third route skips the package manager entirely: a CDN example stands in for an install command, which moves the editor out of your lockfile and into page load.

The value lives in onMount or in onChange, nowhere else

There are two documented ways to read text back, and they attach at different points in the component's life. One keeps the editor instance from the mount callback in a ref and calls getValue on it when you need the current model. The other takes the value straight from an onChange callback, which hands you the current model value along with the change event, so no instance is needed:

javascript
import React from 'react';
import ReactDOM from 'react-dom';

import Editor from '@monaco-editor/react';

function App() {
  function handleEditorChange(value, event) {
    console.log('here is the current model value:', value);
  }

  return (
    <Editor
      height="90vh"
      defaultLanguage="javascript"
      defaultValue="// some comment"
      onChange={handleEditorChange}
    />
  );
}

const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);

The smallest render is one element carrying height, defaultLanguage and defaultValue. Larger examples add onMount, where you receive the editor instance and the monaco instance, plus a before-mount hook that only has the monaco instance because no editor exists yet. The same shape applies to DiffEditor, which takes its own set of options.

Hooks and callbacks cover the rest, with two documented escape hatches

Beyond the value path, the surface is a short list: useMonaco when you need the namespace outside a component's mount, onValidate for the marker array the editor produces as you type, and a loader/config section that sits beside the loader export for the fetch behavior. The multi-model editor is called out as already supported, so several models can sit behind one wrapper instead of one editor component per file. Two escape hatches are documented alongside those defaults: a Create your own editor section for when the built-in props stop short, and a Props section that treats Editor and DiffEditor as separate entries with different option sets. Worth keeping straight while wiring this up: the argument reaching onValidate is the model's markers, and the object saved from onMount is what exposes getValue.

The branch version is a release candidate, and the stable line is fifteen months old

The manifest on the default branch reports 4.8.0-rc.3. The published tags are v4.8.0-rc.3 from 2025-11-21, v4.8.0-rc.0 from 2025-10-12 and v4.7.0 from 2025-02-13, and the last push landed on 2026-04-20. What that means for anyone adopting it is concrete rather than abstract: the 4.8 line has only ever shipped as release candidates, so a team that requires a stable tag sits on the February 2025 release, while a team that wants the React 19 work asks for the @next tag instead of the plain package name. Migration is not guesswork, because the repository keeps a v4.changes.md document for moving off v3 and links the older instructions at the v3.8.3 README. Check which of those two you are reading before copying snippets.

Electron and Next.js get their own notes for a reason

The table of contents carries a Notes heading with separate subsections for electron users and Next.js users, which is the clearest signal in the whole file about where the automatic path ends. Both of those runtimes move the editor payload away from an ordinary browser page load, and a wrapper built so that no bundler configuration is needed cannot decide those questions for you. The two subsections sit next to the multi-model and Create your own editor entries in the same list, so treat them as required reading rather than footnotes. If your app runs inside Electron or is server-rendered with Next.js, assume the one-line integration is a starting point: check the Notes entries before you trust the loader timing, and expect to configure how monaco gets loaded rather than to inherit a finished answer.

Build, test and playground wiring sit in the open

The repository is arranged so the internals can be read instead of only the compiled package. The top level carries tsup.config.ts for the bundle, vitest.config.ts and setupTests.ts for the test run, eslint.config.mjs and .prettierrc.json for lint and format rules, and a .husky/ directory pulled in by the prepare script. The scripts block is short and explicit:

json
"scripts": {
  "lint": "eslint src",
  "build": "tsup",
  "dev": "tsup --watch",
  "prepublishOnly": "npm test && npm run lint && npm run build",
  "prepare": "husky",
  "test": "vitest run"
}

Because prepublishOnly runs the tests, lint and build in that order, a release cannot ship on a branch that fails any of the three. A Development / Playground section in the documentation maps to the playground/ directory, where you can run the library and poke at its internals, and demo/ is a complete Vite app with its own vite.config.ts, tsconfig files and biome.json. Note that demo/dist/ is committed, so that app's build output is part of the tree. tsup.config.ts with types pointed at dist/index.d.ts tells you where the shipped type declarations come from.

Editorial conclusion

Use it when you want a VS Code class editor in a React app and would rather not write bundler plugin configuration, and check the monaco-editor peer version plus the release candidate status of the 4.8 line before you pin anything. Leave it alone if your build already loads monaco-editor by hand, if you cannot add the peer package, or if you need a stable tag rather than an rc, since React 19 support sits on the @next tag.

Frequently asked questions

What is the Monaco editor used for?

monaco-editor is the browser based code editor that powers VS Code. This wrapper loads it into React apps without bundler plugin configuration and exposes an Editor component, a DiffEditor component, the useMonaco hook and the loader utility.

Do I have to install monaco-editor myself to use @monaco-editor/react?

Yes. It is a peer dependency with the range >= 0.25.0 < 1, and the type definitions come from the monaco-editor package, so an app that does not already have it installed needs to add it separately.

Which package tag should I install for React 19?

The install line names @monaco-editor/react@next for React v19. The peer range covers ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 for both react and react-dom, while the 4.8 line itself is published as release candidates.

How do I read the current text out of the editor?

Either store the editor instance from onMount in a ref and call getValue on it, or read the value argument that the onChange callback receives. Both routes appear in the usage sections of the documentation.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. suren-atoyan/monaco-react on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/suren-atoyan-monaco-react.svg)](https://hysenlabs.com/projects/suren-atoyan-monaco-react)