0
# Monaco Diff Editor
1
2
The MonacoDiffEditor component provides side-by-side code comparison functionality with change highlighting, useful for showing differences between code versions, reviewing changes, or implementing merge interfaces.
3
4
## Capabilities
5
6
### Monaco Diff Editor Component
7
8
React component wrapper for Monaco Diff Editor with full TypeScript support and lifecycle management.
9
10
```typescript { .api }
11
/**
12
* Monaco Diff Editor React component for side-by-side code comparison
13
* @param props - MonacoDiffEditorProps configuration
14
* @param ref - Forward ref to access diff editor instance
15
* @returns React element containing Monaco Diff Editor
16
*/
17
declare const MonacoDiffEditor: React.ForwardRefExoticComponent<
18
MonacoDiffEditorProps & React.RefAttributes<MonacoDiffEditorHandle>
19
>;
20
```
21
22
**Usage Examples:**
23
24
```typescript
25
import React, { useState } from "react";
26
import { MonacoDiffEditor } from "react-monaco-editor";
27
28
// Basic diff editor showing changes
29
function BasicDiffEditor() {
30
const originalCode = `function greet(name) {
31
console.log("Hello " + name);
32
}`;
33
34
const modifiedCode = `function greet(name) {
35
console.log(\`Hello \${name}!\`);
36
return \`Hello \${name}!\`;
37
}`;
38
39
return (
40
<MonacoDiffEditor
41
width="800"
42
height="400"
43
language="javascript"
44
original={originalCode}
45
value={modifiedCode}
46
options={{
47
renderSideBySide: true,
48
enableSplitViewResizing: true,
49
readOnly: false,
50
}}
51
/>
52
);
53
}
54
55
// Interactive diff editor with state management
56
function InteractiveDiffEditor() {
57
const [original, setOriginal] = useState('const a = "Hello World";');
58
const [modified, setModified] = useState('const a = "Hello Monaco";');
59
60
return (
61
<div>
62
<div>
63
<button onClick={() => setOriginal('const b = "Updated Original";')}>
64
Update Original
65
</button>
66
<button onClick={() => setModified('const b = "Updated Modified";')}>
67
Update Modified
68
</button>
69
</div>
70
<MonacoDiffEditor
71
width="800"
72
height="300"
73
language="javascript"
74
original={original}
75
value={modified}
76
onChange={(newValue) => setModified(newValue)}
77
editorDidMount={(editor, monaco) => {
78
console.log('Diff editor mounted');
79
}}
80
/>
81
</div>
82
);
83
}
84
```
85
86
### Component Props
87
88
Full configuration interface for the Monaco Diff Editor component.
89
90
```typescript { .api }
91
interface MonacoDiffEditorProps extends MonacoEditorBaseProps {
92
/** The original value to compare against. */
93
original?: string;
94
95
/** Value of the auto created model in the editor.
96
* If you specify value property, the component behaves in controlled mode.
97
* Otherwise, it behaves in uncontrolled mode. */
98
value?: string;
99
100
/** Refer to Monaco interface {monaco.editor.IDiffEditorConstructionOptions}. */
101
options?: monaco.editor.IDiffEditorConstructionOptions;
102
103
/** Refer to Monaco interface {monaco.editor.IEditorOverrideServices}. */
104
overrideServices?: monaco.editor.IEditorOverrideServices;
105
106
/** An event emitted before the editor mounted (similar to componentWillMount of React). */
107
editorWillMount?: DiffEditorWillMount;
108
109
/** An event emitted when the editor has been mounted (similar to componentDidMount of React). */
110
editorDidMount?: DiffEditorDidMount;
111
112
/** An event emitted before the editor unmount (similar to componentWillUnmount of React). */
113
editorWillUnmount?: DiffEditorWillUnmount;
114
115
/** An event emitted when the content of the current model has changed. */
116
onChange?: DiffChangeHandler;
117
118
/** Let the language be inferred from the uri */
119
originalUri?: (monaco: typeof monaco) => monaco.Uri;
120
121
/** Let the language be inferred from the uri */
122
modifiedUri?: (monaco: typeof monaco) => monaco.Uri;
123
}
124
```
125
126
### Diff Editor Handle
127
128
Interface for accessing the Monaco Diff Editor instance via React ref.
129
130
```typescript { .api }
131
interface MonacoDiffEditorHandle {
132
/** Direct access to Monaco diff editor instance */
133
editor: monaco.editor.IStandaloneDiffEditor;
134
}
135
```
136
137
**Usage Example:**
138
139
```typescript
140
import React, { useRef } from "react";
141
import { MonacoDiffEditor } from "react-monaco-editor";
142
143
function DiffEditorWithRef() {
144
const diffEditorRef = useRef<MonacoDiffEditorHandle>(null);
145
146
const getChanges = () => {
147
if (diffEditorRef.current) {
148
const diffEditor = diffEditorRef.current.editor;
149
const changes = diffEditor.getLineChanges();
150
console.log('Line changes:', changes);
151
152
// Access individual editors
153
const originalEditor = diffEditor.getOriginalEditor();
154
const modifiedEditor = diffEditor.getModifiedEditor();
155
156
console.log('Original content:', originalEditor.getValue());
157
console.log('Modified content:', modifiedEditor.getValue());
158
}
159
};
160
161
return (
162
<div>
163
<button onClick={getChanges}>Get Changes</button>
164
<MonacoDiffEditor
165
ref={diffEditorRef}
166
width="800"
167
height="400"
168
language="javascript"
169
original="const original = true;"
170
value="const modified = true;"
171
/>
172
</div>
173
);
174
}
175
```
176
177
### Lifecycle Callbacks
178
179
Callback functions for handling diff editor lifecycle events.
180
181
```typescript { .api }
182
/**
183
* Callback invoked before the diff editor is mounted
184
* @param monaco - Monaco Editor API instance
185
* @returns Optional editor construction options to merge with props.options
186
*/
187
type DiffEditorWillMount = (
188
monaco: typeof monaco
189
) => void | monaco.editor.IStandaloneEditorConstructionOptions;
190
191
/**
192
* Callback invoked after the diff editor has been mounted
193
* @param editor - The mounted Monaco diff editor instance
194
* @param monaco - Monaco Editor API instance
195
*/
196
type DiffEditorDidMount = (
197
editor: monaco.editor.IStandaloneDiffEditor,
198
monaco: typeof monaco
199
) => void;
200
201
/**
202
* Callback invoked before the diff editor is unmounted
203
* @param editor - The Monaco diff editor instance being unmounted
204
* @param monaco - Monaco Editor API instance
205
*/
206
type DiffEditorWillUnmount = (
207
editor: monaco.editor.IStandaloneDiffEditor,
208
monaco: typeof monaco
209
) => void;
210
211
/**
212
* Callback invoked when the modified editor content changes
213
* Note: Only changes to the modified (right-side) editor trigger this callback
214
*/
215
type DiffChangeHandler = ChangeHandler;
216
```
217
218
**Usage Example:**
219
220
```typescript
221
function DiffEditorWithLifecycle() {
222
const diffEditorWillMount = (monaco) => {
223
console.log('Diff editor will mount');
224
// Return options to merge with props.options
225
return {
226
renderSideBySide: true,
227
ignoreTrimWhitespace: false,
228
};
229
};
230
231
const diffEditorDidMount = (diffEditor, monaco) => {
232
console.log('Diff editor mounted');
233
234
// Access both editors
235
const originalEditor = diffEditor.getOriginalEditor();
236
const modifiedEditor = diffEditor.getModifiedEditor();
237
238
// Add commands to both editors
239
const commandId = 'my.custom.command';
240
originalEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK, () => {
241
console.log('Custom command in original editor');
242
});
243
244
modifiedEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK, () => {
245
console.log('Custom command in modified editor');
246
});
247
};
248
249
const diffEditorWillUnmount = (diffEditor, monaco) => {
250
console.log('Diff editor will unmount');
251
// Cleanup if needed
252
};
253
254
const onChange = (newValue, event) => {
255
console.log('Modified editor content changed:', newValue);
256
};
257
258
return (
259
<MonacoDiffEditor
260
width="800"
261
height="400"
262
language="typescript"
263
original="interface User { name: string; }"
264
value="interface User { name: string; age: number; }"
265
editorWillMount={diffEditorWillMount}
266
editorDidMount={diffEditorDidMount}
267
editorWillUnmount={diffEditorWillUnmount}
268
onChange={onChange}
269
/>
270
);
271
}
272
```
273
274
### URI Support
275
276
Custom URI creation for both original and modified models, useful for language services and proper file identification.
277
278
```typescript { .api }
279
/**
280
* Function to create a Monaco URI for the original model
281
* @param monaco - Monaco Editor API instance
282
* @returns Monaco URI for the original model
283
*/
284
originalUri?: (monaco: typeof monaco) => monaco.Uri;
285
286
/**
287
* Function to create a Monaco URI for the modified model
288
* @param monaco - Monaco Editor API instance
289
* @returns Monaco URI for the modified model
290
*/
291
modifiedUri?: (monaco: typeof monaco) => monaco.Uri;
292
```
293
294
**Usage Example:**
295
296
```typescript
297
function DiffEditorWithURIs() {
298
return (
299
<MonacoDiffEditor
300
width="800"
301
height="400"
302
language="typescript"
303
original="// Original version"
304
value="// Modified version"
305
originalUri={(monaco) => monaco.Uri.parse("file:///original.ts")}
306
modifiedUri={(monaco) => monaco.Uri.parse("file:///modified.ts")}
307
/>
308
);
309
}
310
```
311
312
### Common Diff Options
313
314
Frequently used Monaco Diff Editor configuration options:
315
316
```typescript
317
const commonDiffOptions = {
318
// Layout
319
renderSideBySide: true, // Side-by-side view (true) vs inline view (false)
320
enableSplitViewResizing: true, // Allow resizing the split view
321
322
// Whitespace handling
323
ignoreTrimWhitespace: true, // Ignore leading/trailing whitespace changes
324
325
// Line changes
326
renderIndicators: true, // Show change indicators in overview ruler
327
328
// Readonly behavior
329
readOnly: false, // Allow editing the modified version
330
originalEditable: false, // Prevent editing the original version
331
332
// Diff computation
333
maxComputationTime: 5000, // Max time in ms for diff computation
334
335
// Word-level diffing
336
diffWordWrap: 'off' as const, // Word wrap for diff algorithm
337
338
// Colors and styling
339
renderOverviewRuler: true, // Show overview ruler with change markers
340
};
341
```
342
343
### Accessing Individual Editors
344
345
The diff editor provides access to both the original and modified editors:
346
347
```typescript
348
function AccessIndividualEditors() {
349
const diffEditorRef = useRef<MonacoDiffEditorHandle>(null);
350
351
const workWithEditors = () => {
352
if (diffEditorRef.current) {
353
const diffEditor = diffEditorRef.current.editor;
354
355
// Get individual editors
356
const originalEditor = diffEditor.getOriginalEditor();
357
const modifiedEditor = diffEditor.getModifiedEditor();
358
359
// Work with original editor
360
const originalContent = originalEditor.getValue();
361
originalEditor.setSelection(new monaco.Selection(1, 1, 1, 10));
362
363
// Work with modified editor
364
const modifiedContent = modifiedEditor.getValue();
365
modifiedEditor.focus();
366
367
// Get diff information
368
const lineChanges = diffEditor.getLineChanges();
369
console.log('Changes:', lineChanges);
370
}
371
};
372
373
return (
374
<div>
375
<button onClick={workWithEditors}>Work with Editors</button>
376
<MonacoDiffEditor
377
ref={diffEditorRef}
378
width="800"
379
height="400"
380
language="javascript"
381
original="const a = 1;"
382
value="const b = 2;"
383
/>
384
</div>
385
);
386
}
387
```