### Install @monaco-editor/react with Yarn Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Install the @monaco-editor/react package using Yarn. ```bash yarn add @monaco-editor/react ``` -------------------------------- ### Install @monaco-editor/react with npm Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Install the @monaco-editor/react package using npm. Use the @next tag for React v19 compatibility. ```bash npm install @monaco-editor/react # or @monaco-editor/react@next for React v19 ``` -------------------------------- ### loader.init() Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Documentation for the loader.init() method that starts or joins the shared Monaco loading process. ```APIDOC ## loader.init() ### Description Starts or joins the shared Monaco loading process. Returns a cancelable promise that resolves with the Monaco instance. ### Method init ### Parameters None ### Returns - **Promise** - A cancelable promise that resolves with the Monaco instance. ### Example ```javascript import { loader } from '@monaco-editor/react'; loader .init() .then((monaco) => console.log('here is the monaco instance:', monaco)) .catch((error) => { if (error?.type === 'cancelation') return; // cancelled, ignore console.error('Monaco failed to load', error); }); ``` ### Error Handling - **error.type === 'cancelation'** - The load was cancelled; silently ignored. - **any other rejection** - Logged via `console.error('Monaco initialization: error:', error)`. ``` -------------------------------- ### Get monaco instance via loader.init() Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Use the loader utility to get the monaco instance. loader.init() returns a promise that resolves with the monaco instance. ```javascript import { loader } from '@monaco-editor/react'; loader.init().then((monaco) => console.log('here is the monaco instance:', monaco)); ``` -------------------------------- ### Run the playground Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Commands to clone the repository, install dependencies for the library and the playground, and run the playground. The playground is a minimal React app that uses the library sources directly, allowing you to test the freshest state of the library. ```bash git clone https://github.com/suren-atoyan/monaco-react.git ``` ```bash cd monaco-react ``` ```bash npm install # yarn ``` ```bash cd playground ``` ```bash npm install # yarn ``` ```bash npm run dev # yarn dev ``` -------------------------------- ### Get editor instance via onMount Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Use the onMount prop to receive the editor instance as the first parameter. Store it in a ref for later use. The second parameter is the monaco instance. ```javascript 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 ( ); } const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); ``` -------------------------------- ### useMonaco() Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/use-monaco.md Documentation for the useMonaco hook, including its signature, behavior, return type, and usage examples. ```APIDOC ## useMonaco() ### Description Returns the Monaco instance, loading it asynchronously if it has not been loaded yet. The hook is used to access the Monaco editor API for configuration and other operations. ### Signature ```ts function useMonaco(): Monaco | undefined ``` ### Parameters None. ### Return Value - **Monaco | undefined** - The Monaco instance, or `undefined` (or `null` on first render if this hook initiates loading) while loading is in progress. ### Behavior 1. **Initial state:** Seeds state from `loader.__getMonacoInstance()` - the instance Monaco has already stored if another consumer (e.g. an `Editor`) initiated loading first. 2. **If not loaded yet:** Calls `loader.init()`, which starts (or joins) the **single shared, asynchronous** Monaco loading process, and resolves `monaco` into state when ready. 3. **Cancellation:** If the hook's component unmounts while loading is in progress, the returned cleanup calls `cancelable?.cancel()`, which makes the underlying `init()` promise reject with an error of type `'cancelation'`; `useMonaco` attaches no rejection handler, so the cancellation rejection must not be unhandled-promise-observed by the host environment (`@monaco-editor/loader` handles this internally). 4. **Re-renders:** The hook re-renders the component once `monaco` arrives, so downstream effects keyed on `monaco` must be written defensively (conditional chaining). ### Important Note Monaco initialization is performed asynchronously and *only once* (shared via the loader). If `useMonaco` is the first initiator of the initialization, the first returned value will be `null`; re-check the value on subsequent renders. ### Throws / Rejects `useMonaco` never throws synchronously. It does not expose the `init()` promise to the caller, so consumer error handling is done by checking the returned value for truthiness rather than try/catch. ### Examples #### Conditional use after load ```jsx import React, { useEffect } from 'react'; import Editor, { useMonaco } from '@monaco-editor/react'; function App() { const monaco = useMonaco(); useEffect(() => { if (monaco) { console.log('here is the monaco instance:', monaco); // configure language defaults only after monaco exists monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true); } }, [monaco]); return ; } ``` #### Guarded access while loading ```jsx import Editor, { useMonaco } from '@monaco-editor/react'; function App() { const monaco = useMonaco(); // safe anywhere: no-op while monaco is still undefined const addCommand = () => { monaco?.editor.addCommand?.(/* ... */); }; return addCommand()} />; } ``` ### References - Source: `src/hooks/useMonaco/index.ts` - Depends on: `src/hooks/useMount` (internal) and the `@monaco-editor/loader` package (reexported as `loader` from the package root). - Related: [Editor](./editor.md), [loader](./loader.md), [types](../types.md) ``` -------------------------------- ### Get monaco instance via beforeMount/onMount Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Get the monaco instance via the beforeMount and onMount props. beforeMount runs before the editor is mounted and can be used to configure monaco, e.g., setEagerModelSync(true). onMount also receives the monaco instance as the second parameter. ```javascript import 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 ( ); } const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); ``` -------------------------------- ### Create your own editor with loader.init() Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Create a custom editor using the loader utility directly. This is the shortest way to initialize Monaco and create an editor in a plain DOM element. The example sets the wrapper height and provides initial value and language. ```javascript import loader from '@monaco-editor/loader'; loader.init().then((monaco) => { const wrapper = document.getElementById('root'); wrapper.style.height = '100vh'; const properties = { value: 'function hello() {\n\talert("Hello world!");\n}', language: 'javascript', }; monaco.editor.create(wrapper, properties); }); ``` -------------------------------- ### Use monaco-editor with Vite and worker setup Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Use monaco-editor as an npm package with Vite. Sets up MonacoEnvironment workers and configures the loader. Requires the ?worker imports for Vite. ```javascript import { loader } from '@monaco-editor/react'; 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(); }, }; loader.config({ monaco }); loader.init().then(/* ... */); ``` -------------------------------- ### Get value via editor instance Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Get the current editor value by storing the editor instance in a ref via onMount and calling getValue(). ```javascript 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) { editorRef.current = editor; } function showValue() { alert(editorRef.current.getValue()); } return ( <> ); } const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); ``` -------------------------------- ### Configure eslint-plugin-react for type-aware linting Source: https://github.com/suren-atoyan/monaco-react/blob/master/demo/README.md Install eslint-plugin-react and update the ESLint config to set the React version, add the plugin, and enable its recommended rules. This is part of expanding the ESLint configuration for production. ```javascript // eslint.config.js import react from 'eslint-plugin-react' export default tseslint.config({ // Set the react version settings: { react: { version: '18.3' } }, plugins: { // Add the react plugin react, }, rules: { // other rules... // Enable its recommended rules ...react.configs.recommended.rules, ...react.configs['jsx-runtime'].rules, }, }) ``` -------------------------------- ### Configure Monaco loader with custom paths and locale Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/configuration.md Use this example to set a custom base path for the Monaco editor's 'vs' distribution and configure the locale. The 'vs/nls' key sets available languages, here German ('de'). Note that without a custom config, Monaco is loaded from the default CDN sources. ```js import { loader } from '@monaco-editor/react'; loader.config({ paths: { vs: '/local/path/to/monaco/min/vs' }, 'vs/nls': { availableLanguages: { '*': 'de' } }, }); ``` -------------------------------- ### Controlled editor + multi-model through `path` Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/editor.md Controlled editor example that switches between multiple models using the `path` prop. The `value` and `language` props are driven by React state, and buttons change the active file. ```jsx import React, { useState } from 'react'; import Editor from '@monaco-editor/react'; const files = { 'script.js': { language: 'javascript', value: 'const x = 1;' }, 'style.css': { language: 'css', value: 'body { color: red; }' }, }; function App() { const [fileName, setFileName] = useState('script.js'); const file = files[fileName]; return ( <> ); } ``` -------------------------------- ### DiffEditor with per-side languages, named models, and mount callback Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/diff-editor.md Configures a DiffEditor with markdown for both sides, using distinct in-memory model paths. The onMount callback provides access to the inner editors and the Monaco instance, allowing imperative operations like getting values and model count. ```jsx import { DiffEditor } from '@monaco-editor/react'; function App() { const handleMount = (diffEditor, monaco) => { // access the inner editors imperatively console.log(diffEditor.getOriginalEditor().getValue()); console.log(diffEditor.getModifiedEditor().getValue()); console.log(monaco.editor.getModels().length); }; return ( ); } ``` -------------------------------- ### Use monaco-editor as npm package with loader.config({ monaco }) Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Shows how to bundle Monaco yourself and point the loader at it using loader.config({ monaco }). Available starting with v4.4.0. With Vite, you must configure web workers via self.MonacoEnvironment.getWorker before calling this. Bundling may require webpack plugins and may be impossible inside CRA without ejecting. ```javascript import * as monaco from 'monaco-editor'; import { loader } from '@monaco-editor/react'; loader.config({ monaco }); ``` -------------------------------- ### Get value via onChange prop Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Get the current editor value via the onChange prop. The first argument is the current model value. ```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 ( ); } const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); ``` -------------------------------- ### Initiate loading manually with loader.init() Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Shows how to manually initiate loading of Monaco using loader.init(). The returned promise resolves with the Monaco instance. The catch block ignores cancelation errors and logs other failures. ```javascript import { loader } from '@monaco-editor/react'; loader .init() .then((monaco) => console.log('here is the monaco instance:', monaco)) .catch((error) => { if (error?.type === 'cancelation') return; // cancelled, ignore console.error('Monaco failed to load', error); }); ``` -------------------------------- ### Get monaco instance via useMonaco hook Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Use the useMonaco hook to get the monaco instance. The hook returns null initially because initialization is asynchronous; check the value before using it. ```javascript import 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 ; } const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); ``` -------------------------------- ### BeforeMount Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/types.md Callback fired with the Monaco instance before the editor is mounted. Use it to define themes, register providers, or change defaults. ```APIDOC ## BeforeMount ### Description Callback fired with the Monaco instance before the editor is mounted. Use it to define themes, register providers, or change defaults. ### Type Signature ```ts export type BeforeMount = (monaco: Monaco) => void; ``` ### Parameters - **monaco** (Monaco) - Required - The Monaco namespace. ### Usage Used by `EditorProps.beforeMount`. ``` -------------------------------- ### loader.__getMonacoInstance() Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Documentation for the loader.__getMonacoInstance() method that synchronously returns the Monaco instance if available. ```APIDOC ## loader.__getMonacoInstance() ### Description Synchronously returns the already-initialized Monaco instance, or `undefined` if loading has not finished or succeeded. ### Method __getMonacoInstance ### Parameters None ### Returns - **Monaco | undefined** - The Monaco instance if initialized, otherwise `undefined`. ### Example ```javascript import { loader } from '@monaco-editor/react'; const monaco = loader.__getMonacoInstance(); if (monaco) { console.log('Monaco is ready', monaco); } else { console.log('Monaco is not loaded yet'); } ``` ``` -------------------------------- ### Get DiffEditor values via editor instance Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Get the DiffEditor values via the editor instance. Use getOriginalEditor().getValue() and getModifiedEditor().getValue() after storing the editor in a ref via onMount. ```javascript 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 ( <> ); } const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); ``` -------------------------------- ### Import Editor, DiffEditor, useMonaco, and loader Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Import the main components and utilities from the library. This is the recommended way to access Editor, DiffEditor, useMonaco, and loader. ```javascript import Editor, { DiffEditor, useMonaco, loader } from '@monaco-editor/react'; ``` -------------------------------- ### Electron: load from local files with loader.config() Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Shows how to load Monaco from local files instead of a CDN in an Electron environment. It constructs a file:// URI from the local path to the monaco-editor min/vs directory and passes it to loader.config(). ```javascript const path = require('path'); const { loader } = require('@monaco-editor/react'); function ensureFirstBackSlash(str) { return str.length > 0 && str.charAt(0) !== '/' ? '/' + str : str; } function uriFromPath(_path) { const pathName = path.resolve(_path).replace(/\\/g, '/'); return encodeURI('file://' + ensureFirstBackSlash(pathName)); } loader.config({ paths: { vs: uriFromPath(path.join(__dirname, '../node_modules/monaco-editor/min/vs')), }, }); ``` -------------------------------- ### OnMount Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/types.md Callback fired once after the editor is mounted. Receives the editor instance and the Monaco namespace. ```APIDOC ## OnMount ### Description Callback fired once after the editor is mounted. Receives the editor instance and the Monaco namespace. ### Type Signature ```ts export type OnMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void; ``` ### Parameters - **editor** (editor.IStandaloneCodeEditor) - Required - The standalone code editor instance created by `monaco.editor.create`. Methods include `getValue`, `setValue`, `getModel`, `setModel`, `updateOptions`, `revealLine`, `executeEdits`, `pushUndoStop`, `onDidChangeModelContent`, `getOption` / `getOptions`, `saveViewState`, `restoreViewState`, `dispose`. - **monaco** (Monaco) - Required - The Monaco namespace. ### Usage Used by `EditorProps.onMount`; also the callback shape surfaced when consumers keep a reference to the mounted editor. ``` -------------------------------- ### Configure loader with loader.config() Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Shows how to configure the loader using loader.config(). The config object is deep-merged over the default config. Supported keys include paths.vs for the CDN source and 'vs/nls' for locale configuration. ```javascript import { loader } from '@monaco-editor/react'; // change the source of the monaco files (CDN vs local vs bundled) loader.config({ paths: { vs: '...' } }); // configure the locales loader.config({ 'vs/nls': { availableLanguages: { '*': 'de' } } }); // combine multiple keys loader.config({ paths: { vs: '...' }, 'vs/nls': { availableLanguages: { '*': 'de' } }, }); ``` -------------------------------- ### Define file structure object for multi-model editor Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Defines a file structure object with entries for script.js, style.css, and index.html, each containing a name, language, and value. This object is used as the data source for the multi-model editor example. ```javascript const files = { 'script.js': { name: 'script.js', language: 'javascript', value: someJSCodeExample, }, 'style.css': { name: 'style.css', language: 'css', value: someCSSCodeExample, }, 'index.html': { name: 'index.html', language: 'html', value: someHTMLCodeExample, }, }; ``` -------------------------------- ### Catch loader.init() rejection in consumer code Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/errors.md Consumer-side pattern to observe loader.init() rejections because the components swallow them internally. Ignores 'cancelation' errors (expected during unmount) and logs other errors with a custom handler. ```js import { loader } from '@monaco-editor/react'; try { await loader.init(); // rejects on CDN/network/script failure } catch (error) { if (error?.type === 'cancelation') return; // expected during unmount console.error('custom handler:', error); } ``` -------------------------------- ### useMonaco hook implementation (src/hooks/useMonaco/index.ts) Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/use-monaco.md The full implementation of the useMonaco hook. It seeds state from loader.__getMonacoInstance(), calls loader.init() if not loaded, and cancels the pending init on unmount. The returned value is Monaco | undefined; the first value may be null if this hook initiates loading. ```ts // src/hooks/useMonaco/index.ts import { useState } from 'react'; import loader from '@monaco-editor/loader'; import useMount from '../useMount'; function useMonaco() { const [monaco, setMonaco] = useState(loader.__getMonacoInstance()); useMount(() => { let cancelable: ReturnType; if (!monaco) { cancelable = loader.init(); cancelable.then((monaco) => { setMonaco(monaco); }); } return () => cancelable?.cancel(); }); return monaco; } export default useMonaco; ``` -------------------------------- ### loader.config(config) Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Documentation for the loader.config() method that configures the Monaco loader source and options. ```APIDOC ## loader.config(config) ### Description Deep-merges a config object over the package's default config (e.g. CDN `paths.vs`, locale `'vs/nls'`, or a bundled `monaco` instance). ### Method config ### Parameters - **config** (object) - Required - Configuration object to merge over defaults. ### Supported Keys - **paths.vs** (string) - Optional - URL or path to the Monaco editor source. - **'vs/nls'** (object) - Optional - Locale configuration, e.g. `{ availableLanguages: { '*': 'de' } }`. - **monaco** (object) - Optional - A bundled Monaco instance to use instead of loading from CDN. ### Example ```javascript import { loader } from '@monaco-editor/react'; // change the source of the monaco files (CDN vs local vs bundled) loader.config({ paths: { vs: '...' } }); // configure the locales loader.config({ 'vs/nls': { availableLanguages: { '*': 'de' } } }); // combine multiple keys loader.config({ paths: { vs: '...' }, 'vs/nls': { availableLanguages: { '*': 'de' } }, }); // use monaco-editor as an npm package (no CDN) import * as monaco from 'monaco-editor'; loader.config({ monaco }); ``` ``` -------------------------------- ### Handle loader.init() rejection with cancelation check Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/loader.md Shows how the repository handles the rejection of the promise returned by loader.init(). Only the 'cancelation' error type is silently ignored; all other errors are logged via console.error. ```typescript // src/Editor/Editor.tsx:59-62 .catch( (error) => error?.type !== 'cancelation' && console.error('Monaco initialization: error:', error), ); ``` -------------------------------- ### Mounted editor + value change + validation Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/api-reference/editor.md Shows how to access the mounted editor and monaco instance, define a custom theme, and handle value changes and validation markers. The onChange handler logs the changed lines from the event's contentChangedEvent. ```jsx import Editor from '@monaco-editor/react'; function App() { const handleMount = (editor, monaco) => { // e.g. register a keyboard shortcut or a custom completion provider monaco.editor.defineTheme('my-dark', { base: 'vs-dark', inherit: true, rules: [{ token: 'comment', foreground: 'ff0000', fontStyle: 'bold' }], colors: { 'editor.background': '#1e1e1e' }, }); editor.focus(); }; const handleChange = (value, event) => console.log('value:', value, 'changed range:', event.contentChangedEvent.changedLines); const handleValidate = (markers) => markers.forEach((m) => console.log('onValidate:', m.message)); return ( console.log('monaco instance:', monaco)} onMount={handleMount} onChange={handleChange} onValidate={handleValidate} /> ); } ``` -------------------------------- ### OnMount type definition Source: https://github.com/suren-atoyan/monaco-react/blob/master/_autodocs/types.md Defines the callback signature for the editor's onMount prop. Receives the editor instance and the Monaco namespace. Fired once after mounting. ```TypeScript export type OnMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void; ``` -------------------------------- ### Configure loader with loader.config() Source: https://github.com/suren-atoyan/monaco-react/blob/master/README.md Configure the Monaco loader by changing the CDN source of monaco files or setting locales. The passed object is deeply merged with the default config. Use this to customize the AMD loader behavior. ```javascript 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', }, }, }); ```