CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-monaco-editor

React components for integrating Microsoft's Monaco Editor into React applications

Pending
Overview
Eval results
Files

diff-editor.mddocs/

Monaco Diff Editor

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.

Capabilities

Monaco Diff Editor Component

React component wrapper for Monaco Diff Editor with full TypeScript support and lifecycle management.

/**
 * Monaco Diff Editor React component for side-by-side code comparison
 * @param props - MonacoDiffEditorProps configuration
 * @param ref - Forward ref to access diff editor instance
 * @returns React element containing Monaco Diff Editor
 */
declare const MonacoDiffEditor: React.ForwardRefExoticComponent<
  MonacoDiffEditorProps & React.RefAttributes<MonacoDiffEditorHandle>
>;

Usage Examples:

import React, { useState } from "react";
import { MonacoDiffEditor } from "react-monaco-editor";

// Basic diff editor showing changes
function BasicDiffEditor() {
  const originalCode = `function greet(name) {
  console.log("Hello " + name);
}`;

  const modifiedCode = `function greet(name) {
  console.log(\`Hello \${name}!\`);
  return \`Hello \${name}!\`;
}`;

  return (
    <MonacoDiffEditor
      width="800"
      height="400"
      language="javascript"
      original={originalCode}
      value={modifiedCode}
      options={{
        renderSideBySide: true,
        enableSplitViewResizing: true,
        readOnly: false,
      }}
    />
  );
}

// Interactive diff editor with state management
function InteractiveDiffEditor() {
  const [original, setOriginal] = useState('const a = "Hello World";');
  const [modified, setModified] = useState('const a = "Hello Monaco";');

  return (
    <div>
      <div>
        <button onClick={() => setOriginal('const b = "Updated Original";')}>
          Update Original
        </button>
        <button onClick={() => setModified('const b = "Updated Modified";')}>
          Update Modified
        </button>
      </div>
      <MonacoDiffEditor
        width="800"
        height="300"
        language="javascript"
        original={original}
        value={modified}
        onChange={(newValue) => setModified(newValue)}
        editorDidMount={(editor, monaco) => {
          console.log('Diff editor mounted');
        }}
      />
    </div>
  );
}

Component Props

Full configuration interface for the Monaco Diff Editor component.

interface MonacoDiffEditorProps extends MonacoEditorBaseProps {
  /** The original value to compare against. */
  original?: string;

  /** Value of the auto created model in the editor.
   * If you specify value property, the component behaves in controlled mode. 
   * Otherwise, it behaves in uncontrolled mode. */
  value?: string;

  /** Refer to Monaco interface {monaco.editor.IDiffEditorConstructionOptions}. */
  options?: monaco.editor.IDiffEditorConstructionOptions;

  /** Refer to Monaco interface {monaco.editor.IEditorOverrideServices}. */
  overrideServices?: monaco.editor.IEditorOverrideServices;

  /** An event emitted before the editor mounted (similar to componentWillMount of React). */
  editorWillMount?: DiffEditorWillMount;

  /** An event emitted when the editor has been mounted (similar to componentDidMount of React). */
  editorDidMount?: DiffEditorDidMount;

  /** An event emitted before the editor unmount (similar to componentWillUnmount of React). */
  editorWillUnmount?: DiffEditorWillUnmount;

  /** An event emitted when the content of the current model has changed. */
  onChange?: DiffChangeHandler;

  /** Let the language be inferred from the uri */
  originalUri?: (monaco: typeof monaco) => monaco.Uri;

  /** Let the language be inferred from the uri */
  modifiedUri?: (monaco: typeof monaco) => monaco.Uri;
}

Diff Editor Handle

Interface for accessing the Monaco Diff Editor instance via React ref.

interface MonacoDiffEditorHandle {
  /** Direct access to Monaco diff editor instance */
  editor: monaco.editor.IStandaloneDiffEditor;
}

Usage Example:

import React, { useRef } from "react";
import { MonacoDiffEditor } from "react-monaco-editor";

function DiffEditorWithRef() {
  const diffEditorRef = useRef<MonacoDiffEditorHandle>(null);

  const getChanges = () => {
    if (diffEditorRef.current) {
      const diffEditor = diffEditorRef.current.editor;
      const changes = diffEditor.getLineChanges();
      console.log('Line changes:', changes);
      
      // Access individual editors
      const originalEditor = diffEditor.getOriginalEditor();
      const modifiedEditor = diffEditor.getModifiedEditor();
      
      console.log('Original content:', originalEditor.getValue());
      console.log('Modified content:', modifiedEditor.getValue());
    }
  };

  return (
    <div>
      <button onClick={getChanges}>Get Changes</button>
      <MonacoDiffEditor
        ref={diffEditorRef}
        width="800"
        height="400"
        language="javascript"
        original="const original = true;"
        value="const modified = true;"
      />
    </div>
  );
}

Lifecycle Callbacks

Callback functions for handling diff editor lifecycle events.

/**
 * Callback invoked before the diff editor is mounted
 * @param monaco - Monaco Editor API instance
 * @returns Optional editor construction options to merge with props.options
 */
type DiffEditorWillMount = (
  monaco: typeof monaco
) => void | monaco.editor.IStandaloneEditorConstructionOptions;

/**
 * Callback invoked after the diff editor has been mounted
 * @param editor - The mounted Monaco diff editor instance
 * @param monaco - Monaco Editor API instance
 */
type DiffEditorDidMount = (
  editor: monaco.editor.IStandaloneDiffEditor,
  monaco: typeof monaco
) => void;

/**
 * Callback invoked before the diff editor is unmounted
 * @param editor - The Monaco diff editor instance being unmounted
 * @param monaco - Monaco Editor API instance
 */
type DiffEditorWillUnmount = (
  editor: monaco.editor.IStandaloneDiffEditor,
  monaco: typeof monaco
) => void;

/**
 * Callback invoked when the modified editor content changes
 * Note: Only changes to the modified (right-side) editor trigger this callback
 */
type DiffChangeHandler = ChangeHandler;

Usage Example:

function DiffEditorWithLifecycle() {
  const diffEditorWillMount = (monaco) => {
    console.log('Diff editor will mount');
    // Return options to merge with props.options
    return {
      renderSideBySide: true,
      ignoreTrimWhitespace: false,
    };
  };

  const diffEditorDidMount = (diffEditor, monaco) => {
    console.log('Diff editor mounted');
    
    // Access both editors
    const originalEditor = diffEditor.getOriginalEditor();
    const modifiedEditor = diffEditor.getModifiedEditor();
    
    // Add commands to both editors
    const commandId = 'my.custom.command';
    originalEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK, () => {
      console.log('Custom command in original editor');
    });
    
    modifiedEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK, () => {
      console.log('Custom command in modified editor');
    });
  };

  const diffEditorWillUnmount = (diffEditor, monaco) => {
    console.log('Diff editor will unmount');
    // Cleanup if needed
  };

  const onChange = (newValue, event) => {
    console.log('Modified editor content changed:', newValue);
  };

  return (
    <MonacoDiffEditor
      width="800"
      height="400"
      language="typescript"
      original="interface User { name: string; }"
      value="interface User { name: string; age: number; }"
      editorWillMount={diffEditorWillMount}
      editorDidMount={diffEditorDidMount}
      editorWillUnmount={diffEditorWillUnmount}
      onChange={onChange}
    />
  );
}

URI Support

Custom URI creation for both original and modified models, useful for language services and proper file identification.

/**
 * Function to create a Monaco URI for the original model
 * @param monaco - Monaco Editor API instance
 * @returns Monaco URI for the original model
 */
originalUri?: (monaco: typeof monaco) => monaco.Uri;

/**
 * Function to create a Monaco URI for the modified model
 * @param monaco - Monaco Editor API instance
 * @returns Monaco URI for the modified model
 */
modifiedUri?: (monaco: typeof monaco) => monaco.Uri;

Usage Example:

function DiffEditorWithURIs() {
  return (
    <MonacoDiffEditor
      width="800"
      height="400"
      language="typescript"
      original="// Original version"
      value="// Modified version"
      originalUri={(monaco) => monaco.Uri.parse("file:///original.ts")}
      modifiedUri={(monaco) => monaco.Uri.parse("file:///modified.ts")}
    />
  );
}

Common Diff Options

Frequently used Monaco Diff Editor configuration options:

const commonDiffOptions = {
  // Layout
  renderSideBySide: true,          // Side-by-side view (true) vs inline view (false)
  enableSplitViewResizing: true,   // Allow resizing the split view
  
  // Whitespace handling
  ignoreTrimWhitespace: true,      // Ignore leading/trailing whitespace changes
  
  // Line changes
  renderIndicators: true,          // Show change indicators in overview ruler
  
  // Readonly behavior
  readOnly: false,                 // Allow editing the modified version
  originalEditable: false,         // Prevent editing the original version
  
  // Diff computation
  maxComputationTime: 5000,        // Max time in ms for diff computation
  
  // Word-level diffing
  diffWordWrap: 'off' as const,    // Word wrap for diff algorithm
  
  // Colors and styling
  renderOverviewRuler: true,       // Show overview ruler with change markers
};

Accessing Individual Editors

The diff editor provides access to both the original and modified editors:

function AccessIndividualEditors() {
  const diffEditorRef = useRef<MonacoDiffEditorHandle>(null);

  const workWithEditors = () => {
    if (diffEditorRef.current) {
      const diffEditor = diffEditorRef.current.editor;
      
      // Get individual editors
      const originalEditor = diffEditor.getOriginalEditor();
      const modifiedEditor = diffEditor.getModifiedEditor();
      
      // Work with original editor
      const originalContent = originalEditor.getValue();
      originalEditor.setSelection(new monaco.Selection(1, 1, 1, 10));
      
      // Work with modified editor
      const modifiedContent = modifiedEditor.getValue();
      modifiedEditor.focus();
      
      // Get diff information
      const lineChanges = diffEditor.getLineChanges();
      console.log('Changes:', lineChanges);
    }
  };

  return (
    <div>
      <button onClick={workWithEditors}>Work with Editors</button>
      <MonacoDiffEditor
        ref={diffEditorRef}
        width="800"
        height="400"
        language="javascript"
        original="const a = 1;"
        value="const b = 2;"
      />
    </div>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-react-monaco-editor

docs

diff-editor.md

index.md

monaco-editor.md

tile.json