Monaco Editor for React · use the monaco-editor in any React application without needing to use webpack (or rollup/parcel/etc) configuration files / plugins
v19 users: check out the v4.7.0-rc.0 version (use npm install @monaco-editor/react@next or yarn add @monaco-editor/react@next) and let us know if you face any issuesTypeScript :fire:v4 is here - to see what's new in the new version and how to migrate from v3, please read this doc (also, if you need the old version README, it's here)Monaco editor wrapper for easy/one-line integration with any React application without needing to use webpack (or any other module bundler) configuration files / plugins. It can be used with apps generated by create-react-app, create-snowpack-app, vite, Next.js or any other app generators - you don't need to eject or rewire them.
The monaco-editor is a well-known web technology based code editor that powers VS Code. This library handles the setup process of the monaco-editor and provides a clean API to interact with monaco from any React environment
editor instancemonaco instanceuseMonacoloader/configonValidateEditorDiff Editornpm install @monaco-editor/react # or @monaco-editor/react@next for React v19
or
yarn add @monaco-editor/react
or you can use CDN. Here is an example
NOTE: For TypeScript type definitions, this package uses the monaco-editor package as a peer dependency. So, if you need types and don't already have the monaco-editor package installed, you will need to do so
Monaco-React AI will help you understand this repository better. You can ask for code examples, installation guide, debugging help and much more.
Besides types, the library exports Editorand DiffEditor components, as well as the loader utility and the useMonaco hook:
import Editor, { DiffEditor, useMonaco, loader } from '@monaco-editor/react';
Here is an example of a simple integration of monaco editor with a React project.
You just need to import and render the Editor component:
import React from 'react';
import ReactDOM from 'react-dom';
import Editor from '@monaco-editor/react';
function App() {
return <Editor height="90vh" defaultLanguage="javascript" defaultValue="// some comment" />;
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
Extended example
import React from 'react';
import ReactDOM from 'react-dom';
import Editor from '@monaco-editor/react';
function App() {
function handleEditorChange(value, event) {
// here is the current value
}
function handleEditorDidMount(editor, monaco) {
console.log('onMount: the editor instance:', editor);
console.log('onMount: the monaco instance:', monaco);
}
function handleEditorWillMount(monaco) {
console.log('beforeMount: the monaco instance:', monaco);
}
function handleEditorValidation(markers) {
// model markers
// markers.forEach(marker => console.log('onValidate:', marker.message));
}
return (
<Editor
height="90vh"
defaultLanguage="javascript"
defaultValue="// some comment"
onChange={handleEditorChange}
onMount={handleEditorDidMount}
beforeMount={handleEditorWillMount}
onValidate={handleEditorValidation}
/>
);
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
There are two options to get the current value:
editor instanceimport React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import Editor from '@monaco-editor/react';
function App() {
const editorRef = useRef(null);
function handleEditorDidMount(editor, monaco) {
editorRef.current = editor;
}
function showValue() {
alert(editorRef.current.getValue());
}
return (
<>
<button onClick={showValue}>Show value</button>
<Editor
height="90vh"
defaultLanguage="javascript"
defaultValue="// some comment"
onMount={handleEditorDidMount}
/>
</>
);
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
onChange propimport 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);
(get the DiffEditor values via editor instance)
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import { DiffEditor } from '@monaco-editor/react';
function App() {
const diffEditorRef = useRef(null);
function handleEditorDidMount(editor, monaco) {
diffEditorRef.current = editor;
}
function showOriginalValue() {
alert(diffEditorRef.current.getOriginalEditor().getValue());
}
function showModifiedValue() {
alert(diffEditorRef.current.getModifiedEditor().getValue());
}
return (
<>
<button onClick={showOriginalValue}>show original value</button>
<button onClick={showModifiedValue}>show modified value</button>
<DiffEditor
height="90vh"
language="javascript"
original="// the original code"
modified="// the modified code"
onMount={handleEditorDidMount}
/>
</>
);
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
editor instanceThe editor instance is exposed from the onMount prop as a first parameter, the second is the monaco instance
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import Editor from '@monaco-editor/react';
function App() {
const editorRef = useRef(null);
function handleEditorDidMount(editor, monaco) {
// here is the editor instance
// you can store it in `useRef` for further usage
editorRef.current = editor;
}
return (
<Editor
height="90vh"
defaultLanguage="javascript"
defaultValue="// some comment"
onMount={handleEditorDidMount}
/>
);
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
monaco instanceThere are three options to get the monaco instance:
onMount/beforeMountimport React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import Editor from '@monaco-editor/react';
function App() {
const monacoRef = useRef(null);
function handleEditorWillMount(monaco) {
// here is the monaco instance
// do something before editor is mounted
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
}
function handleEditorDidMount(editor, monaco) {
// here is another way to get monaco instance
// you can also store it in `useRef` for further usage
monacoRef.current = monaco;
}
return (
<Editor
height="90vh"
defaultLanguage="javascript"
defaultValue="// some comment"
beforeMount={handleEditorWillMount}
onMount={handleEditorDidMount}
/>
);
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
loader utilityimport { loader } from '@monaco-editor/react';
loader.init().then((monaco) => console.log('here is the monaco instance:', monaco));
useMonaco hookimport React from 'react';
import ReactDOM from 'react-dom';
import Editor, { useMonaco } from '@monaco-editor/react';
function App() {
const monaco = useMonaco();
useEffect(() => {
if (monaco) {
console.log('here is the monaco instance:', monaco);
}
}, [monaco]);
return <Editor height="90vh" defaultValue="// some comment" defaultLanguage="javascript" />;
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
useMonacouseMonaco is a React hook that returns the instance of the monaco. But there is an important note that should be considered: the initialization process is being handled by the loader utility (the reference of @monaco-editor/loader): that process is being done asynchronously and only once. So, if the first initiator of the initialization is useMonaco hook, the first returned value will be null, due to its asynchronous installation. Just check the returned value of useMonaco
import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';
import Editor, { useMonaco } from '@monaco-editor/react';
function App() {
const monaco = useMonaco();
useEffect(() => {
// do conditional chaining
monaco?.languages.typescript.javascriptDefaults.setEagerModelSync(true);
// or make sure that it exists by other ways
if (monaco) {
console.log('here is the monaco instance:', monaco);
}
}, [monaco]);
return <Editor height="90vh" defaultValue="// some comment" defaultLanguage="javascript" />;
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
loader-configThe library exports (named) the utility called loader. Basically, it's the reference of @monaco-editor/loader. By default, monaco files are being downloaded from CDN. There is an ability to change this behavior, and other things concerning the AMD loader of monaco. We have a default config file that you can modify by the way shown below:
import { loader } from '@monaco-editor/react';
// you can change the source of the monaco files
loader.config({ paths: { vs: '...' } });
// you can configure the locales
loader.config({ 'vs/nls': { availableLanguages: { '*': 'de' } } });
// or
loader.config({
paths: {
vs: '...',
},
'vs/nls': {
availableLanguages: {
'*': 'de',
},
},
});
monaco-editor as an npm packageStarting from version v4.4.0 it's possible to use monaco-editor as an npm package; import it from node_modules and include monaco sou
$ claude mcp add monaco-react \
-- python -m otcore.mcp_server <graph>