Monaco Editor for React - use the monaco-editor in any React application without needing to use webpack (or rollup/parcel/etc) configuration files / plugins
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The primary Monaco Editor React component providing full code editing capabilities with syntax highlighting, IntelliSense, autocomplete, and advanced editing features for any programming language.
Main editor component that wraps Monaco Editor with React-friendly props and event handling.
/**
* Monaco Editor React component with full editing capabilities
* @param props - Editor configuration and event handlers
* @returns React component rendering Monaco Editor
*/
declare const Editor: React.ComponentType<EditorProps>;
interface EditorProps {
/** Default value of the current model */
defaultValue?: string;
/** Value of the current model (controlled) */
value?: string;
/** Default language of the current model */
defaultLanguage?: string;
/** Language of the current model */
language?: string;
/** Default path of the current model - passed to monaco.editor.createModel */
defaultPath?: string;
/** Path of the current model - passed to monaco.editor.createModel */
path?: string;
/** Theme for the monaco editor - 'vs-dark' | 'light' or custom theme name */
theme?: Theme | string;
/** Line number to jump to when editor mounts */
line?: number;
/** Loading component shown before editor is mounted */
loading?: ReactNode;
/** Monaco editor construction options */
options?: editor.IStandaloneEditorConstructionOptions;
/** Editor service overrides */
overrideServices?: editor.IEditorOverrideServices;
/** Whether to save view states between model changes */
saveViewState?: boolean;
/** Whether to keep current model when component unmounts */
keepCurrentModel?: boolean;
/** Width of editor wrapper */
width?: number | string;
/** Height of editor wrapper */
height?: number | string;
/** CSS class name for editor container */
className?: string;
/** Props applied to the wrapper element */
wrapperProps?: object;
/** Called before editor is mounted with monaco instance */
beforeMount?: BeforeMount;
/** Called when editor is mounted with editor and monaco instances */
onMount?: OnMount;
/** Called when editor content changes */
onChange?: OnChange;
/** Called when model validation completes */
onValidate?: OnValidate;
}Usage Examples:
import React, { useState } from "react";
import Editor from "@monaco-editor/react";
// Basic editor
function BasicEditor() {
return (
<Editor
height="400px"
defaultLanguage="javascript"
defaultValue="console.log('Hello Monaco!');"
/>
);
}
// Controlled editor with change handling
function ControlledEditor() {
const [code, setCode] = useState("const greeting = 'Hello World';");
const handleEditorChange = (value) => {
setCode(value || "");
};
return (
<Editor
height="400px"
language="javascript"
value={code}
onChange={handleEditorChange}
options={{
minimap: { enabled: false },
fontSize: 14,
}}
/>
);
}
// Multi-model editor
function MultiModelEditor() {
const [currentFile, setCurrentFile] = useState("file1.js");
const files = {
"file1.js": "console.log('File 1');",
"file2.ts": "const message: string = 'File 2';",
"file3.py": "print('File 3')"
};
return (
<div>
<select onChange={(e) => setCurrentFile(e.target.value)}>
{Object.keys(files).map(filename => (
<option key={filename} value={filename}>{filename}</option>
))}
</select>
<Editor
height="400px"
path={currentFile}
defaultLanguage={currentFile.split('.').pop()}
value={files[currentFile]}
options={{ readOnly: false }}
/>
</div>
);
}Event handler functions for responding to editor lifecycle and content changes.
/**
* Called when editor is mounted - provides access to editor and monaco instances
* @param editor - The standalone code editor instance
* @param monaco - The monaco editor namespace
*/
type OnMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void;
/**
* Called before editor is mounted - allows monaco configuration
* @param monaco - The monaco editor namespace
*/
type BeforeMount = (monaco: Monaco) => void;
/**
* Called when editor content changes
* @param value - Current editor value (may be undefined)
* @param event - Monaco content change event with details
*/
type OnChange = (value: string | undefined, ev: editor.IModelContentChangedEvent) => void;
/**
* Called when model validation completes with error/warning markers
* @param markers - Array of validation markers (errors, warnings, info)
*/
type OnValidate = (markers: editor.IMarker[]) => void;Event Handler Examples:
import Editor from "@monaco-editor/react";
function EditorWithHandlers() {
const handleBeforeMount = (monaco) => {
// Configure monaco before editor creation
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
// Define custom theme
monaco.editor.defineTheme('myTheme', {
base: 'vs-dark',
inherit: true,
rules: [],
colors: {
'editor.background': '#1e1e1e',
}
});
};
const handleMount = (editor, monaco) => {
// Configure editor after mount
editor.focus();
editor.setPosition({ lineNumber: 1, column: 1 });
// Add custom commands
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
console.log('Save command triggered');
});
};
const handleChange = (value, event) => {
console.log('Content changed:', value);
console.log('Change details:', event);
};
const handleValidate = (markers) => {
// Handle validation errors/warnings
const errors = markers.filter(m => m.severity === 8); // Error severity
const warnings = markers.filter(m => m.severity === 4); // Warning severity
console.log(`Validation: ${errors.length} errors, ${warnings.length} warnings`);
};
return (
<Editor
height="400px"
defaultLanguage="javascript"
beforeMount={handleBeforeMount}
onMount={handleMount}
onChange={handleChange}
onValidate={handleValidate}
theme="myTheme"
/>
);
}Configuration options for customizing editor behavior and appearance.
// Core configuration props
interface EditorSizingProps {
/** Width of editor wrapper - default "100%" */
width?: number | string;
/** Height of editor wrapper - default "100%" */
height?: number | string;
/** CSS class name for editor container */
className?: string;
/** Props applied to wrapper element */
wrapperProps?: object;
}
interface EditorContentProps {
/** Initial editor content */
defaultValue?: string;
/** Controlled editor content */
value?: string;
/** Initial language mode */
defaultLanguage?: string;
/** Current language mode */
language?: string;
/** Initial model path/URI */
defaultPath?: string;
/** Current model path/URI */
path?: string;
}
interface EditorBehaviorProps {
/** Editor theme name */
theme?: Theme | string;
/** Line to jump to on mount */
line?: number;
/** Loading component during initialization */
loading?: ReactNode;
/** Save view state between model changes */
saveViewState?: boolean;
/** Keep model when unmounting */
keepCurrentModel?: boolean;
}
// Monaco editor native options (from monaco-editor package)
interface EditorMonacoOptions {
/** Monaco editor construction options */
options?: editor.IStandaloneEditorConstructionOptions;
/** Service overrides for advanced customization */
overrideServices?: editor.IEditorOverrideServices;
}Configuration Examples:
import Editor from "@monaco-editor/react";
// Customized editor appearance and behavior
function CustomizedEditor() {
const editorOptions = {
fontSize: 16,
lineHeight: 24,
minimap: { enabled: true },
scrollBeyondLastLine: false,
wordWrap: 'on',
automaticLayout: true,
tabSize: 2,
insertSpaces: true,
renderLineHighlight: 'all',
selectOnLineNumbers: true,
glyphMargin: true,
folding: true,
lineNumbers: 'on',
scrollbar: {
vertical: 'visible',
horizontal: 'visible',
},
};
return (
<Editor
height="500px"
width="100%"
language="typescript"
theme="vs-dark"
options={editorOptions}
className="custom-editor"
wrapperProps={{ style: { border: '1px solid #ccc' } }}
saveViewState={true}
keepCurrentModel={false}
/>
);
}The editor supports multi-model functionality for working with multiple files or code snippets.
// Model-related props
interface ModelProps {
/** Path identifies the model - models are cached by path */
path?: string;
/** Whether to dispose model when component unmounts */
keepCurrentModel?: boolean;
/** Save editor view state (cursor, scroll) when switching models */
saveViewState?: boolean;
}Multi-Model Example:
// File tab editor with model persistence
function FileTabEditor() {
const [activeFile, setActiveFile] = useState('main.js');
const files = {
'main.js': { language: 'javascript', content: 'console.log("main");' },
'utils.ts': { language: 'typescript', content: 'export const util = () => {};' },
'styles.css': { language: 'css', content: 'body { margin: 0; }' },
};
return (
<div>
<div>
{Object.keys(files).map(filename => (
<button
key={filename}
onClick={() => setActiveFile(filename)}
style={{
fontWeight: activeFile === filename ? 'bold' : 'normal'
}}
>
{filename}
</button>
))}
</div>
<Editor
height="400px"
path={activeFile}
language={files[activeFile].language}
defaultValue={files[activeFile].content}
saveViewState={true} // Preserves cursor position per file
keepCurrentModel={true} // Keeps models in memory
/>
</div>
);
}