codemirror, monaco-editor, and react-codemirror2 are libraries used to embed rich text and code editing capabilities into web applications. codemirror (specifically version 6) is a modular, lightweight editor core designed for extensibility and performance. monaco-editor is the powerful engine behind VS Code, offering deep language intelligence and IDE-like features out of the box. react-codemirror2 is a React wrapper built around the older CodeMirror version 5, providing easier integration for React apps but relying on legacy architecture.
Building a code editor into a web app is a complex task. You need syntax highlighting, line numbers, key bindings, and often language intelligence. codemirror, monaco-editor, and react-codemirror2 approach this problem differently. Let's look at how they handle setup, customization, and React integration.
codemirror (Version 6) is built as a set of small, interchangeable modules.
// codemirror: Modular setup
import { EditorState } from "@codemirror/state";
import { EditorView, basicSetup } from "@codemirror/view";
import { javascript } from "@codemirror/lang-javascript";
const state = EditorState.create({
doc: "console.log('hello')",
extensions: [basicSetup, javascript()]
});
const view = new EditorView({ state, parent: document.getElementById("editor") });
monaco-editor is a large, monolithic engine.
// monaco-editor: Monolithic setup
import * as monaco from 'monaco-editor';
monaco.editor.create(document.getElementById("editor"), {
value: "console.log('hello')",
language: "javascript",
theme: "vs-dark"
});
react-codemirror2 wraps the older CodeMirror 5 architecture.
CodeMirror object from version 5.// react-codemirror2: Legacy wrapper setup
import { Controlled as CodeMirror } from 'react-codemirror2';
import 'codemirror/lib/codemirror.css';
import 'codemirror/mode/javascript/javascript';
function Editor({ code }) {
return (
<CodeMirror
value={code}
options={{ mode: 'javascript', lineNumbers: true }}
/>
);
}
codemirror does not ship with official React components.
useEffect hooks.// codemirror: Manual React binding
useEffect(() => {
const view = new EditorView({ /* config */ });
return () => view.destroy(); // Manual cleanup required
}, []);
monaco-editor also requires manual React binding.
// monaco-editor: Manual React binding
useEffect(() => {
const editor = monaco.editor.create(containerRef.current, { /* config */ });
return () => editor.dispose(); // Manual disposal required
}, []);
react-codemirror2 provides a ready-made React component.
// react-codemirror2: Built-in React component
// No useEffect needed for basic mounting
<CodeMirror
value={code}
onChange={(editor, data, value) => setValue(value)}
/>
codemirror uses CSS variables and extension-based theming.
/* codemirror: CSS variable theming */
.cm-editor {
--cm-background: #f0f0f0;
--cm-text: #333;
}
monaco-editor uses predefined themes or JSON configuration.
// monaco-editor: API theming
monaco.editor.defineTheme('myTheme', {
base: 'vs-dark',
inherit: true,
rules: [{ token: 'comment', foreground: 'ffa500' }]
});
react-codemirror2 relies on CodeMirror 5 CSS files.
codemirror/theme/material.css).// react-codemirror2: CSS import theming
import 'codemirror/theme/material.css';
// In component options
options={{ theme: 'material' }}
codemirror uses language extensions.
@codemirror/lang-python).// codemirror: Adding language support
import { python } from "@codemirror/lang-python";
import { linter } from "@codemirror/lint";
extensions: [python(), linter(myLinter)]
monaco-editor has rich language support built-in.
// monaco-editor: Built-in language features
// TypeScript IntelliSense works out of the box
language: "typescript"
react-codemirror2 uses CodeMirror 5 modes.
// react-codemirror2: Importing modes
import 'codemirror/mode/python/python';
options={{ mode: 'python' }}
This is a critical factor for long-term projects.
| Package | Core Version | Status | Recommendation |
|---|---|---|---|
codemirror | Version 6 | ā Active | Recommended for new projects. |
monaco-editor | Latest | ā Active | Recommended for IDE-like tools. |
react-codemirror2 | Version 5 | ā ļø Legacy | Avoid for new projects. Use CM6 wrappers instead. |
CodeMirror 5 is in maintenance mode. It will receive security fixes but no new features. CodeMirror 6 is a complete rewrite with better performance and accessibility. react-codemirror2 does not support CodeMirror 6. If you need React integration with CodeMirror 6, look for community-maintained wrappers like @uiw/react-codemirror.
codemirror is the best choice if you want full control and a small footprint. It requires more code to set up, especially in React, but it scales well and is modern. Use this for custom text inputs, lightweight editors, or when you want to build your own React wrapper.
monaco-editor is the best choice if you want a VS Code experience. It is heavy and harder to style, but the language intelligence is unmatched. Use this for online IDEs, complex configuration editors, or when developer productivity features are the top priority.
react-codemirror2 is the easiest to drop into a React app quickly, but it comes with technical debt. It locks you into an older version of the editor. Use this only for fixing bugs in old apps. For new React apps, pair codemirror (v6) with a modern wrapper instead.
| Feature | codemirror (v6) | monaco-editor | react-codemirror2 (v5) |
|---|---|---|---|
| Bundle Size | Small (Modular) | Large (Monolithic) | Medium (Legacy) |
| React Support | Manual (or 3rd party) | Manual (or 3rd party) | Built-in Component |
| Language Intelligence | Via Extensions | Built-in (VS Code level) | Limited (Modes) |
| Theming | CSS Variables | API / JSON | CSS Files |
| Long-Term Support | ā High | ā High | ā ļø Low (Legacy Core) |
| Setup Complexity | High | Medium | Low |
When choosing an editor, think about your end users and your team. If your users need IntelliSense and debugging tools, monaco-editor is worth the weight. If you need a fast, customizable input for a blog or documentation site, codemirror v6 is the standard. Avoid react-codemirror2 for greenfield development because it ties you to a legacy core, but recognize it as a viable shortcut for maintaining older systems.
Choose codemirror if you need a modern, lightweight editor core and are comfortable building React bindings yourself or using a community wrapper. It is ideal for custom editors where bundle size and modularity matter more than pre-built IDE features. This is the future-proof choice as version 6 is actively developed.
Choose monaco-editor if your application requires advanced language features like IntelliSense, go-to-definition, and rich hover information similar to VS Code. It is best for heavy-duty developer tools, in-browser IDEs, or scenarios where the large bundle size is acceptable for the feature set.
Choose react-codemirror2 only if you are maintaining an existing application already using CodeMirror 5. For new projects, avoid this package because it wraps a legacy version of the core editor. Instead, consider modern alternatives that support CodeMirror 6 for better performance and long-term support.
[ WEBSITE | DOCS | ISSUES | FORUM | CHANGELOG ]
This package provides an example configuration for the
CodeMirror code editor. The actual editor
is implemented in the various packages under the @codemirror scope,
which this package depends on.
The project page has more information, a number of examples and the documentation.
This code is released under an MIT license.
We aim to be an inclusive, welcoming community. To make that explicit, we have a code of conduct that applies to communication around the project.
import {EditorView, basicSetup} from "codemirror"
const view = new EditorView({
parent: document.body,
doc: "Hello",
extensions: [basicSetup /* ... */]
})
This sets up a basic code editor containing the word "Hello". You'll usually want to add at least a language mode to your configuration.