![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@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 · use the monaco-editor in any React application without needing to use webpack
(or rollup
/parcel
/etc) configuration files / plugins
:tada: version v4
is here - to see what's new in the new version and how to migrate from v3
, please read this doc
:tada: the new section Development / Playground has been created - now you can run the playground and play with the internals of the library
:tada: it's already integrated with @monaco-editor/loader
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 gererators - you don't need to eject or rewire them. You can use it even from CDN without budlers
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
npm install @monaco-editor/react
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
Besides types, the library exports Editor
and 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"
language="javascript"
defaultValue="// some comment"
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
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"
language="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"
language="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"
language="javascript"
defaultValue="// some comment"
onChange={handleEditorChange}
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
editor instance
The 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"
language="javascript"
defaultValue="// some comment"
onMount={handleEditorDidMount}
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
monaco instance
There are three options to get the monaco
instance:
onMount/beforeMount
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 = editor;
}
return (
<Editor
height="90vh"
language="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 isntance:", 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 isntance:", monaco);
}
}, [monaco]);
return (
<Editor
height="90vh"
defaultValue="// some comment"
language="javascript"
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
useMonaco
useMonaco
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"
language="javascript"
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
loader-config
The 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",
},
},
});
NOTE: your passed object will be deeply merged with the default one
uncontrolled-controlled modes
Like usual input
element, monaco
editor also maintains its state. But, unlike usual input
element, it's uncommon to circulate the whole state of the editor in your component. Usually you don't need it. If you specify the value
property, the component behaves in controlled
mode, otherwise - in uncontrolled
mode. Usually uncontrolled
mode is used 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. And we highly recommend using that one.
So, if you want to get the current value, you always can use the editor
instance to do so - editor.getValue()
or use onChange
prop to get it. Here are the examples. But in any case controlled
mode is also available
onValidate
onValidate
is an additional property. An event is emitted when the length of the model markers of the current model isn't 0. After each change, if you have some syntax error or some kind of warnings, it will be fired with the current markers
import React from "react";
import ReactDOM from "react-dom";
import Editor from "@monaco-editor/react";
function App() {
function handleEditorValidation(markers) {
// model markers
markers.forEach(marker => console.log('onValidate:', marker.message));
}
return (
<Editor
height="90vh"
language="javascript"
defaultValue="// let's write some broken code 😈"
onValidate={handleEditorValidation}
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
It's important to mention that according to monaco-editor, the whole supported languages are divided into two groups:
IntelliSense
and validationTypeScript
JavaScript
CSS
LESS
SCSS
JSON
HTML
XML
PHP
C#
C++
Razor
Markdown
Diff
Java
VB
CoffeeScript
Handlebars
Batch
Pug
F#
Lua
Powershell
Python
Ruby
SASS
R
Objective-C
As you can guess, onValidate
prop will work only with the languages from the first group
electron
usersAs a usual React
component, this one also works fine with an electron-react environment, without need to have a webpack
configuration or other extra things. But there are several cases that developers usually face to and sometimes it can be confusing. Here they are:
monaco
sources from CDN
. You can see the default configuration. But sure you can change that behavior; the library is fully configurable. Read about it here. So, if you want to download it from your local files, you can do it like this:import { monaco } from '@monaco-editor/react';
monaco.config({ paths: { vs: '../path-to-monaco' } });
monaco-editor
package installed and you want to load monaco from the node_modules
rather than from CDN: in that case, you can write something like this: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));
}
monaco.config({
paths: {
vs: uriFromPath(
path.join(__dirname, '../node_modules/monaco-editor/min/vs')
)
}
});
There were several issues about this topic that can be helpful too - 1 2 3 4
And if you use electron
with monaco
and react
and have faced an issue different than the above-discribed ones, please let us know to make this section more helpful
Next.js
usersLike other React components, this one also works with Next.js
without a hitch. The part of the source that should be pre-parsed is optimized for server-side rendering, so, in usual cases, it will work fine, but if you want to have access, for example, to monaco instance
you should be aware that it wants to access the document
object, and it requires browser environment. Basically you just need to avoid running that part out of browser environment, there are several ways to do that. The one is described here
And if you use monaco
with Next.js
and have faced an issue different than the above-described one, please let us know to make this section more helpful
Under the hood this library uses @monaco-editor/loader that provides a utility called loader
. The loader
utility is a collection of functions that are being used to setup monaco
editor into your browser. loader.init()
handles the whole initialization process and returns the instance of the monaco
- loader.init().then(monaco => console.log("here is the monaco isntance:", monaco))
. The Editor
component uses this utility, gains access to monaco instance
and creates the editor. Here is the implementation of the Editor
component. You can use the same technique to create your own Editor
. You can just import the loader
utility, access to monaco instance
, and create your own editor with your own custom logic. The shortest way to do it:
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);
});
That's all. You can wrap it into a React
component, or Vue
, or Angular
or leave it as vanilla one or whatever you want; it's written in pure js
It's always important to have a place, where you can play with the internals of the library. The playground
is a minimal React
app that directly uses the sources of the library. So, if you are going to open a PR
, or want to check something, or just want to try the freshest state of the library, you can run the playground and enjoy it
git clone https://github.com/suren-atoyan/monaco-react.git
cd monaco-react
npm install # yarn
cd playground
npm install # yarn
npm run dev # yarn dev
monaco-react
├── playground
│ ├── src/ # playground sources
├── src/ # library sources
└── ...
If you want to change something in the library, go to monaco-react/src/...
, the library will be automatically re-built and the playground will use the latest build
Editor
Name | Type | Default | Description |
---|---|---|---|
defaultValue | string | The initial value of the default (auto created) model | |
value | string | Value of the current model | |
language | enum: ... | Language of the current model (all languages that are supported by monaco-editor) | |
defaultModelPath | string | Path for the default (auto created) model. Will be passed as the third argument to .createModel method - monaco.editor.createModel(..., ..., monaco.Uri.parse(defaultModelPath)) | |
theme | enum: "light" | "vs-dark" | "light" | The theme for the monaco. Available options "vs-dark" | "light". Define new themes by monaco.editor.defineTheme |
line | number | The line to jump on it | |
loading | React Node | "Loading..." | The loading screen before the editor will be mounted |
options | object | {} | IStandaloneEditorConstructionOptions |
overrideServices | object | {} | IEditorOverrideServices |
width | union: number | string | "100%" | Width of the editor wrapper |
height | union: number | string | "100%" | Height of the editor wrapper |
className | string | Class name for the editor container | |
wrapperClassName | string | Class name for the editor container wrapper | |
beforeMount | func | noop | Signature: function(monaco: Monaco) => void An event is emitted before the editor is mounted. It gets the monaco instance as a first argument |
onMount | func | noop | Signature: function(editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => void An event is emitted when the editor is mounted. It gets the editor instance as a first argument and the monaco instance as a second |
onChange | func | Signature: function(value: string | undefined, ev: monaco.editor.IModelContentChangedEvent) => void An event is emitted when the content of the current model is changed | |
onValidate | func | noop | Signature: function(markers: monaco.editor.IMarker[]) => void An event is emitted when the length of the model markers of the current model isn't 0 |
DiffEditor
Name | Type | Default | Description |
---|---|---|---|
original | string | The original source (left one) value | |
modified | string | The modified source (right one) value | |
language | enum: ... | Language for the both models - original and modified (all languages that are supported by monaco-editor) | |
originalLanguage | enum: ... | This prop gives you the opportunity to specify the language of the original source separately, otherwise, it will get the value of the language property | |
modifiedLanguage | enum: ... | This prop gives you the opportunity to specify the language of the modified source separately, otherwise, it will get the value of language property | |
originalModelPath | string | Path for the "original" model. Will be passed as a third argument to .createModel method - monaco.editor.createModel(..., ..., monaco.Uri.parse(originalModelPath)) | |
modifiedModelPath | string | Path for the "modified" model. Will be passed as a third argument to .createModel method - monaco.editor.createModel(..., ..., monaco.Uri.parse(modifiedModelPath)) | |
theme | enum: "light" | "vs-dark" | "light" | The theme for the monaco. Available options "vs-dark" | "light". Define new themes by monaco.editor.defineTheme |
line | number | The line to jump on it | |
loading | React Node | "Loading..." | The loading screen before the editor will be mounted |
options | object | {} | IDiffEditorConstructionOptions |
width | union: number | string | "100%" | Width of the editor wrapper |
height | union: number | string | "100%" | Height of the editor wrapper |
className | string | Class name for the editor container | |
wrapperClassName | string | Class name for the editor container wrapper | |
beforeMount | func | noop | Signature: function(monaco: Monaco) => void An event is emitted before the editor mounted. It gets the monaco instance as a first argument |
onMount | func | noop | Signature: function(editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => void An event is emitted when the editor is mounted. It gets the editor instance as a first argument and the monaco instance as a second |
4.0.0
@monaco-editor/loader
) version to - v1.0.0
useMonaco
hookuseMonaco
from the entry fileeditorDidMount
to onMount
onMount
as a second argument (first is the editor instance)beforeMount
prop: function with a single argument -> monaco instancedefaultModelPath
prop, use it as a default model pathdefaultValue
prop and use it during default model creationonChange
prop) to listen default model content change_isControlledMode
proporiginalModelPath
and modifiedModelPath
props, use them as model paths for original/modified modelsEditor
component, now, handles both controlled and uncontrolled modesprop-types
to dependenciesonValidate
prop: an event emitted when the length of the model markers of the current model isn't 0FAQs
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
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.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.