![Create React App Officially Deprecated Amid React 19 Compatibility Issues](https://cdn.sanity.io/images/cgdhsj6q/production/04fa08cf844d798abc0e1a6391c129363cc7e2ab-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Create React App Officially Deprecated Amid React 19 Compatibility Issues
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
@monaco-editor/react
Advanced tools
Monaco editor wrapper for easy/one-line integration with React applications (e.g. powered by create-react-app) without need of webpack configuration files
@monaco-editor/react is a React component for integrating the Monaco Editor, which is the code editor that powers Visual Studio Code, into React applications. It provides a simple way to embed a powerful code editor with syntax highlighting, IntelliSense, and other advanced features.
Basic Usage
This code demonstrates how to use the @monaco-editor/react package to embed a basic Monaco Editor instance in a React application. The editor is set to use JavaScript language and the 'vs-dark' theme.
import React from 'react';
import { MonacoEditor } from '@monaco-editor/react';
function App() {
return (
<div>
<MonacoEditor height="90vh" language="javascript" theme="vs-dark" />
</div>
);
}
export default App;
Customizing Editor Options
This example shows how to customize the editor options. The options object allows you to configure various aspects of the editor, such as making it read-only, changing the cursor style, and enabling automatic layout.
import React from 'react';
import { MonacoEditor } from '@monaco-editor/react';
function App() {
const options = {
selectOnLineNumbers: true,
roundedSelection: false,
readOnly: true,
cursorStyle: 'line',
automaticLayout: true
};
return (
<div>
<MonacoEditor height="90vh" language="javascript" theme="vs-dark" options={options} />
</div>
);
}
export default App;
Handling Editor Events
This example demonstrates how to handle editor events, such as content changes. The onChange prop is used to pass a callback function that will be called whenever the editor's content changes.
import React from 'react';
import { MonacoEditor } from '@monaco-editor/react';
function App() {
const handleEditorChange = (value, event) => {
console.log('Editor content changed:', value);
};
return (
<div>
<MonacoEditor height="90vh" language="javascript" theme="vs-dark" onChange={handleEditorChange} />
</div>
);
}
export default App;
react-ace is a React component for the Ace editor, another popular code editor. It offers similar features like syntax highlighting, themes, and various editor options. However, Monaco Editor is generally considered more powerful and feature-rich, especially for larger projects.
react-codemirror2 is a React component for the CodeMirror editor. It provides a highly customizable code editor with support for many languages and themes. While CodeMirror is lightweight and fast, Monaco Editor offers more advanced features like IntelliSense and better integration with TypeScript.
react-simple-code-editor is a lightweight code editor component for React. It is built on top of Prism.js for syntax highlighting. While it is simpler and easier to use, it lacks many of the advanced features found in Monaco Editor, such as IntelliSense and comprehensive language support.
Monaco Editor for React
Monaco editor wrapper for easy/one-line integration with React applications without need of webpack (or other module bundler) configuration files.
There is a well-known web technology based code editor called Monaco Editor that powers VS Code. There are also many ways to integrate it provided by monaco creators. But there were tons of problems with integration of monaco with modern technologies; e.g React.
There also exist solutions for integration with React; e.g this one and this one. But they need some custom webpack configuration to make Monaco fully work, which is not the "best" solution for such kind of things like create-react-app - CRA.
With this solution, you don't need any kind of webpack configuration files and it works great with React apps created by CRA or created by something else.
npm install @monaco-editor/react
or
yarn add @monaco-editor/react
NOTE: for type definitions, this package uses monaco-editor package and it is defined as a peer dependency. So, if you need types and you have not monaco-editor npm package installed in your project, you have to install it by yourself.
Besides types three main components are also exported from the package:
And the utility that gives ability to access to monaco instance (simply called "monaco")
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. You can play with it here
import React from "react";
import ReactDOM from "react-dom";
import Editor from '@monaco-editor/react';
const App = _ => <Editor height="90vh" language="javascript" />;
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Editor from "@monaco-editor/react";
import { FillSpinner as Loader } from "react-spinners-kit";
import examples from "./examples";
function App() {
const [theme, setTheme] = useState("light");
const [language, setLanguage] = useState("javascript");
const [isEditorReady, setIsEditorReady] = useState(false);
function handleEditorDidMount() {
setIsEditorReady(true);
}
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
function toggleLanguage() {
setLanguage(language === "javascript" ? "python" : "javascript");
}
return (
<>
<button onClick={toggleTheme} disabled={!isEditorReady}>
Toggle theme
</button>
<button onClick={toggleLanguage} disabled={!isEditorReady}>
Toggle language
</button>
<Editor
height="90vh" // By default, it fully fits with its parent
theme={theme}
language={language}
loading={<Loader />}
value={examples[language]}
editorDidMount={handleEditorDidMount}
options={{ lineNumbers: "off" }}
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You can play with it here
You may ask how we can get the value of the editor. There is a prop called editorDidMount
. It gets two arguments: the first one is a function to get editor value, the second one is the editor instance.
Here is an example of how you can implement it.
You can play with it here
import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import Editor from "@monaco-editor/react";
function App() {
const [isEditorReady, setIsEditorReady] = useState(false);
const valueGetter = useRef();
function handleEditorDidMount(_valueGetter) {
setIsEditorReady(true);
valueGetter.current = _valueGetter;
}
function handleShowValue() {
alert(valueGetter.current());
}
return (
<>
<button onClick={handleShowValue} disabled={!isEditorReady}>
Show value
</button>
<Editor
height="90vh"
language="javascript"
value={"// write your code here"}
editorDidMount={handleEditorDidMount}
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
If you want to create your own language or theme, or modify existing ones you may need to access to the monaco instance. So, to that purpose, there is a utility called "monaco" exported from library and you can use it like this:
import { monaco } from '@monaco-editor/react';
monaco
.init()
.then(monaco => {/* here is the instance of monaco, so you can use the `monaco.languages` or whatever you want */})
.catch(error => console.error('An error occurred during initialization of Monaco: ', error));
You can play with it here
By default, monaco files are being downloaded from CDN. There is an ability to change this behavior, and other things concerning the AMD loader. We have a default config file you can modify it by the shown way.
import { monaco } from '@monaco-editor/react';
// you can change the source of the monaco files
monaco.config({ paths: { vs: '...' } });
// you can configure the locales
monaco.config({ 'vs/nls': { availableLanguages: { '*': 'de' } } });
// or
monaco.config({
paths: {
vs: '...',
},
'vs/nls' : {
availableLanguages: {
'*': 'de',
},
},
});
NOTE: your passed object will be deeply merged with the default one.
It's handy to have access to the editor instance for some reason.
As we have already mentioned, the editorDidMount
prop gets the editor instance as a second argument.
Here is an example of how you can use the editor instance.
You can play with it here
import React, { useRef } from "react";
import ReactDOM from "react-dom";
import Editor from "@monaco-editor/react";
function App() {
const editorRef = useRef();
function handleEditorDidMount(_, editor) {
editorRef.current = editor;
// Now you can use the instance of monaco editor
// in this component whenever you want
}
function listenEditorChanges() {
editorRef.current.onDidChangeModelContent(ev => {
console.log(editorRef.current.getValue());
});
}
return (
<>
<button onClick={listenEditorChanges} disabled={!!editorRef.current}>
Press to listen editor changes (see console)
</button>
<Editor
height="90vh"
editorDidMount={handleEditorDidMount}
language="javascript"
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
The default export of the library is uncontrolled react component:
import Editor from '@monaco-editor/react'
We make it by default uncontrolled to keep the nature of the monaco editor as much as it is possible. And based on our experience we can say that in most cases it will cover your needs, as you can see in the examples above. And we highly recommend using that one.
But in any case, if you want a controlled one, there is an option for that. The library exports ControlledEditor
(as named export). It is the same as the default one (Editor
), plus it has onChange
method. It is working a little bit different comparing with, for example, the controlled input
field.
Here is onChange
prop, it will be called each time when the content of the editor is changed. It gets two arguments, first one is the "event" object of monaco, the second one is the current value of the editor.
You can use it without circulating the data, and just by returning it from onChange
simple setting the new value; see the example (You can play with it here)
import React from "react";
import ReactDOM from "react-dom";
import { ControlledEditor } from "@monaco-editor/react";
const BAD_WORD = "eval";
const WARNING_MESSAGE = " <- hey man, what's this?";
function App() {
const handleEditorChange = (ev, value) => {
return value.includes(BAD_WORD) && !value.includes(WARNING_MESSAGE)
? value.replace(BAD_WORD, BAD_WORD + WARNING_MESSAGE)
: value.includes(WARNING_MESSAGE) && !value.includes(BAD_WORD)
? value.replace(WARNING_MESSAGE, "")
: value;
};
return (
<ControlledEditor
height="90vh"
value={"// try to write e%v%a%l somewhere 😈 \n"}
onChange={handleEditorChange}
language="javascript"
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Or like in usual controlled components; see the example (You can play with it here)
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { ControlledEditor } from "@monaco-editor/react";
const BAD_WORD = "eval";
const WARNING_MESSAGE = " <- hey man, what's this?";
function App() {
const [value, setValue] = useState("// try to write e%v%a%l somewhere 😈 \n");
const handleEditorChange = (ev, value) => {
setValue(
value.includes(BAD_WORD) && !value.includes(WARNING_MESSAGE)
? value.replace(BAD_WORD, BAD_WORD + WARNING_MESSAGE)
: value.includes(WARNING_MESSAGE) && !value.includes(BAD_WORD)
? value.replace(WARNING_MESSAGE, "")
: value
);
};
return (
<ControlledEditor
height="90vh"
value={value}
onChange={handleEditorChange}
language="javascript"
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
import React from "react";
import ReactDOM from "react-dom";
import { ControlledEditor } from "@monaco-editor/react";
function App() {
const handleEditorChange = (ev, value) => {
return `"it doesn't matter what you are writing, I am staying here!!!"`;
};
return (
<ControlledEditor
height="90vh"
onChange={handleEditorChange}
language="javascript"
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You can play with it here
Name | Type | Default | Description |
---|---|---|---|
value | string | The editor value | |
language | enum: ... | All languages that are supported by monaco-editor | |
editorDidMount | func | noop | Signature: function(getEditorValue: func, monaco: object) => void This function will be called right after monaco editor is mounted and is ready to work. It will get the editor instance as a second argument |
theme | enum: 'light' | 'dark' | 'light' | Default themes of monaco |
line | number | The line to jump on it | |
width | union: number | string | '100%' | The width of the editor wrapper |
height | union: number | string | '100%' | The height of the editor wrapper |
loading | union: React element | string | 'Loading...' | The loading screen before the editor is loaded |
options | object | {} | IEditorOptions |
className | string | monaco container className | |
wrapperClassName | string | monaco container wrapper className |
Name | Type | Default | Description |
---|---|---|---|
original | string | The original source (left one) value | |
modified | string | The modified source (right one) value | |
language | enum: ... | All languages that are supported by monaco-editor | |
originalLanguage | enum: ... | *language | This prop gives you the opportunity to specify the language of the original source separately, otherwise, it will get the value of language property. (Possible values are the same as language ) |
modifiedLanguage | enum: ... | *language | This prop gives you the opportunity to specify the language of the modified source separately, otherwise, it will get the value of language property. (Possible values are the same as language ) |
editorDidMount | func | noop | Signature: function(getModifiedEditorValue: func, getOriginalEditorValue: func, monaco: object) => void This function will be called right after monaco editor is mounted and is ready to work. It will get the editor instance as a third argument |
theme | enum: 'light' | 'dark' | 'light' | Default themes of monaco |
width | union: number | string | '100%' | The width of the editor wrapper |
height | union: number | string | '100%' | The height of the editor wrapper |
loading | union: React element | string | 'Loading...' | The loading screen before the editor is loaded |
options | object | {} | IDiffEditorOptions |
className | string | monaco container className | |
wrapperClassName | string | monaco container wrapper className |
Extended from Editor (the same props as in Editor plus onChange introduced below)
Name | Type | Default | Description |
---|---|---|---|
onChange | func | noop | Signature: function(ev: any, value: string | undefined) => string | undefined onChange method of monaco editor. It will be called right after the content of the current model is changed. It gets two arguments: first one is the "event" object of monaco, second one is the current value. NOTE: onChange can return the new value, which will be inserted to editor |
3.6.0
FAQs
Monaco Editor for React - use the monaco-editor in any React application without needing to use webpack (or rollup/parcel/etc) configuration files / plugins
The npm package @monaco-editor/react receives a total of 875,967 weekly downloads. As such, @monaco-editor/react popularity was classified as popular.
We found that @monaco-editor/react demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.