0
# Monaco Hook
1
2
React hook for accessing the Monaco Editor instance and its APIs across components without needing to pass instances through props.
3
4
## Capabilities
5
6
### useMonaco Hook
7
8
React hook that provides access to the Monaco Editor instance once it's loaded.
9
10
```typescript { .api }
11
/**
12
* React hook for accessing the Monaco Editor instance
13
* @returns Monaco instance or null if not yet loaded
14
*/
15
function useMonaco(): Monaco | null;
16
17
type Monaco = typeof monaco;
18
```
19
20
**Usage Examples:**
21
22
```typescript
23
import React, { useEffect } from "react";
24
import { useMonaco } from "@monaco-editor/react";
25
26
// Basic Monaco instance access
27
function MonacoStatus() {
28
const monaco = useMonaco();
29
30
useEffect(() => {
31
if (monaco) {
32
console.log("Monaco Editor is ready!");
33
console.log("Available languages:", monaco.languages.getLanguages());
34
}
35
}, [monaco]);
36
37
return (
38
<div>
39
Monaco Status: {monaco ? "Loaded" : "Loading..."}
40
</div>
41
);
42
}
43
44
// Custom language configuration
45
function CustomLanguageSetup() {
46
const monaco = useMonaco();
47
48
useEffect(() => {
49
if (!monaco) return;
50
51
// Register custom language
52
monaco.languages.register({ id: 'myLang' });
53
54
// Define language syntax
55
monaco.languages.setMonarchTokensProvider('myLang', {
56
tokenizer: {
57
root: [
58
[/\[error.*/, "custom-error"],
59
[/\[notice.*/, "custom-notice"],
60
[/\[info.*/, "custom-info"],
61
[/\[[a-zA-Z 0-9:]+\]/, "custom-date"],
62
]
63
}
64
});
65
66
// Configure language features
67
monaco.languages.setLanguageConfiguration('myLang', {
68
brackets: [
69
['[', ']'],
70
['(', ')'],
71
['{', '}']
72
],
73
autoClosingPairs: [
74
{ open: '[', close: ']' },
75
{ open: '(', close: ')' },
76
{ open: '{', close: '}' },
77
]
78
});
79
80
}, [monaco]);
81
82
return <div>Custom language configured</div>;
83
}
84
```
85
86
### Theme Management
87
88
Use the Monaco instance to define and manage custom themes across your application.
89
90
```typescript { .api }
91
// Theme definition interface (from Monaco Editor)
92
interface ThemeDefinition {
93
base: 'vs' | 'vs-dark' | 'hc-black';
94
inherit: boolean;
95
rules: TokenThemeRule[];
96
colors: { [colorId: string]: string };
97
}
98
99
interface TokenThemeRule {
100
token: string;
101
foreground?: string;
102
background?: string;
103
fontStyle?: string;
104
}
105
```
106
107
**Theme Examples:**
108
109
```typescript
110
import React, { useEffect } from "react";
111
import { useMonaco } from "@monaco-editor/react";
112
113
function ThemeManager() {
114
const monaco = useMonaco();
115
116
useEffect(() => {
117
if (!monaco) return;
118
119
// Define custom dark theme
120
monaco.editor.defineTheme('customDark', {
121
base: 'vs-dark',
122
inherit: true,
123
rules: [
124
{ token: 'comment', foreground: '6A9955', fontStyle: 'italic' },
125
{ token: 'keyword', foreground: '569CD6', fontStyle: 'bold' },
126
{ token: 'string', foreground: 'CE9178' },
127
{ token: 'number', foreground: 'B5CEA8' },
128
],
129
colors: {
130
'editor.background': '#1e1e1e',
131
'editor.foreground': '#d4d4d4',
132
'editorLineNumber.foreground': '#858585',
133
'editorCursor.foreground': '#ffffff',
134
'editor.selectionBackground': '#264f78',
135
'editor.lineHighlightBackground': '#2d2d30',
136
}
137
});
138
139
// Define custom light theme
140
monaco.editor.defineTheme('customLight', {
141
base: 'vs',
142
inherit: true,
143
rules: [
144
{ token: 'comment', foreground: '008000', fontStyle: 'italic' },
145
{ token: 'keyword', foreground: '0000ff', fontStyle: 'bold' },
146
{ token: 'string', foreground: 'a31515' },
147
{ token: 'number', foreground: '098658' },
148
],
149
colors: {
150
'editor.background': '#ffffff',
151
'editor.foreground': '#000000',
152
'editorLineNumber.foreground': '#237893',
153
'editor.selectionBackground': '#add6ff',
154
'editor.lineHighlightBackground': '#f0f0f0',
155
}
156
});
157
158
}, [monaco]);
159
160
const applyTheme = (themeName) => {
161
if (monaco) {
162
monaco.editor.setTheme(themeName);
163
}
164
};
165
166
return (
167
<div>
168
<button onClick={() => applyTheme('customDark')}>Dark Theme</button>
169
<button onClick={() => applyTheme('customLight')}>Light Theme</button>
170
<button onClick={() => applyTheme('vs-dark')}>VS Dark</button>
171
<button onClick={() => applyTheme('vs')}>VS Light</button>
172
</div>
173
);
174
}
175
```
176
177
### Language Service Configuration
178
179
Configure TypeScript/JavaScript language services and other language features.
180
181
```typescript { .api }
182
// Language service configuration interfaces (from Monaco Editor)
183
interface LanguageServiceDefaults {
184
setCompilerOptions(options: CompilerOptions): void;
185
setDiagnosticsOptions(options: DiagnosticsOptions): void;
186
addExtraLib(content: string, filePath?: string): void;
187
setEagerModelSync(value: boolean): void;
188
}
189
```
190
191
**Language Service Examples:**
192
193
```typescript
194
import React, { useEffect } from "react";
195
import { useMonaco } from "@monaco-editor/react";
196
197
function TypeScriptConfiguration() {
198
const monaco = useMonaco();
199
200
useEffect(() => {
201
if (!monaco) return;
202
203
// Configure TypeScript compiler options
204
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
205
target: monaco.languages.typescript.ScriptTarget.ES2020,
206
allowNonTsExtensions: true,
207
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
208
module: monaco.languages.typescript.ModuleKind.CommonJS,
209
noEmit: true,
210
esModuleInterop: true,
211
jsx: monaco.languages.typescript.JsxEmit.React,
212
reactNamespace: "React",
213
allowJs: true,
214
typeRoots: ["node_modules/@types"]
215
});
216
217
// Configure diagnostics
218
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
219
noSemanticValidation: false,
220
noSyntaxValidation: false,
221
noSuggestionDiagnostics: false
222
});
223
224
// Add type definitions
225
const reactTypes = `
226
declare module "react" {
227
export interface FC<P = {}> {
228
(props: P & { children?: ReactNode }): ReactElement | null;
229
}
230
export type ReactNode = ReactElement | string | number | boolean | null | undefined;
231
export interface ReactElement<P = any> {
232
type: string | FC<P>;
233
props: P;
234
key: string | number | null;
235
}
236
}
237
`;
238
239
monaco.languages.typescript.typescriptDefaults.addExtraLib(
240
reactTypes,
241
'file:///node_modules/@types/react/index.d.ts'
242
);
243
244
// Enable eager model sync for better performance
245
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);
246
247
}, [monaco]);
248
249
return <div>TypeScript language service configured</div>;
250
}
251
252
function CustomCompletionProvider() {
253
const monaco = useMonaco();
254
255
useEffect(() => {
256
if (!monaco) return;
257
258
// Register custom completion provider
259
const disposable = monaco.languages.registerCompletionItemProvider('javascript', {
260
provideCompletionItems: (model, position) => {
261
const suggestions = [
262
{
263
label: 'console.log',
264
kind: monaco.languages.CompletionItemKind.Function,
265
documentation: 'Log a message to the console',
266
insertText: 'console.log($1);',
267
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
268
range: {
269
startLineNumber: position.lineNumber,
270
endLineNumber: position.lineNumber,
271
startColumn: position.column,
272
endColumn: position.column
273
}
274
},
275
{
276
label: 'async function',
277
kind: monaco.languages.CompletionItemKind.Snippet,
278
documentation: 'Create an async function',
279
insertText: 'async function ${1:functionName}(${2:params}) {\n\t$0\n}',
280
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
281
range: {
282
startLineNumber: position.lineNumber,
283
endLineNumber: position.lineNumber,
284
startColumn: position.column,
285
endColumn: position.column
286
}
287
}
288
];
289
290
return { suggestions };
291
}
292
});
293
294
// Cleanup on unmount
295
return () => disposable.dispose();
296
}, [monaco]);
297
298
return <div>Custom completion provider registered</div>;
299
}
300
```
301
302
### Global Monaco Configuration
303
304
Configure Monaco Editor settings that apply to all editor instances.
305
306
```typescript { .api }
307
// Global configuration options
308
interface GlobalMonacoConfig {
309
/** Configure default options for all editors */
310
setGlobalOptions(options: editor.IEditorOptions): void;
311
/** Register global commands */
312
addGlobalCommand(keybinding: number, handler: () => void): void;
313
/** Configure language features globally */
314
configureLanguageGlobally(languageId: string, config: any): void;
315
}
316
```
317
318
**Global Configuration Examples:**
319
320
```typescript
321
import React, { useEffect } from "react";
322
import { useMonaco } from "@monaco-editor/react";
323
324
function GlobalMonacoSetup() {
325
const monaco = useMonaco();
326
327
useEffect(() => {
328
if (!monaco) return;
329
330
// Set global editor defaults
331
monaco.editor.EditorOptions.fontSize.defaultValue = 14;
332
monaco.editor.EditorOptions.fontFamily.defaultValue = 'Monaco, Menlo, monospace';
333
monaco.editor.EditorOptions.lineHeight.defaultValue = 1.6;
334
335
// Configure global key bindings
336
const formatAction = {
337
id: 'format-document',
338
label: 'Format Document',
339
keybindings: [monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.KeyF],
340
run: (editor) => {
341
editor.getAction('editor.action.formatDocument').run();
342
}
343
};
344
345
// Register global actions
346
monaco.editor.addEditorAction(formatAction);
347
348
// Configure language defaults
349
const jsDefaults = monaco.languages.typescript.javascriptDefaults;
350
jsDefaults.setCompilerOptions({
351
allowNonTsExtensions: true,
352
allowJs: true
353
});
354
355
}, [monaco]);
356
357
return <div>Global Monaco configuration applied</div>;
358
}
359
```
360
361
## Integration Patterns
362
363
### Provider Pattern
364
365
Create a Monaco context provider for app-wide access.
366
367
```typescript
368
import React, { createContext, useContext, useEffect, useState } from "react";
369
import { useMonaco } from "@monaco-editor/react";
370
371
const MonacoContext = createContext(null);
372
373
export function MonacoProvider({ children }) {
374
const monaco = useMonaco();
375
const [isConfigured, setIsConfigured] = useState(false);
376
377
useEffect(() => {
378
if (!monaco || isConfigured) return;
379
380
// Apply global configuration
381
monaco.editor.defineTheme('appTheme', {
382
base: 'vs-dark',
383
inherit: true,
384
rules: [],
385
colors: {
386
'editor.background': '#1a1a1a',
387
}
388
});
389
390
setIsConfigured(true);
391
}, [monaco, isConfigured]);
392
393
return (
394
<MonacoContext.Provider value={{ monaco, isConfigured }}>
395
{children}
396
</MonacoContext.Provider>
397
);
398
}
399
400
export function useAppMonaco() {
401
const context = useContext(MonacoContext);
402
if (!context) {
403
throw new Error('useAppMonaco must be used within MonacoProvider');
404
}
405
return context;
406
}
407
```
408
409
### Conditional Rendering
410
411
Only render Monaco-dependent components after Monaco is loaded.
412
413
```typescript
414
import React from "react";
415
import { useMonaco } from "@monaco-editor/react";
416
import Editor from "@monaco-editor/react";
417
418
function ConditionalEditor() {
419
const monaco = useMonaco();
420
421
if (!monaco) {
422
return <div>Loading Monaco Editor...</div>;
423
}
424
425
return (
426
<div>
427
<Editor
428
height="400px"
429
language="javascript"
430
defaultValue="// Monaco is ready!"
431
/>
432
</div>
433
);
434
}
435
```