CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-monaco-editor--react

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
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

diff-editor.mddocs/

Diff Editor

Side-by-side code comparison editor for visualizing differences between two versions of code. Perfect for code reviews, version comparisons, and merge conflict resolution.

Capabilities

DiffEditor Component

Monaco Diff Editor component that displays two code versions side-by-side with highlighted differences.

/**
 * Monaco Diff Editor React component for comparing two code versions
 * @param props - Diff editor configuration and content
 * @returns React component rendering Monaco Diff Editor
 */
declare const DiffEditor: React.ComponentType<DiffEditorProps>;

interface DiffEditorProps {
  /** Original source (left side) value */
  original?: string;
  /** Modified source (right side) value */
  modified?: string;
  /** Language for both models */
  language?: string;
  /** Language for original model only */
  originalLanguage?: string;
  /** Language for modified model only */
  modifiedLanguage?: string;
  /** Path for the original model */
  originalModelPath?: string;
  /** Path for the modified model */
  modifiedModelPath?: string;
  /** Whether to keep original model when unmounting */
  keepCurrentOriginalModel?: boolean;
  /** Whether to keep modified model when unmounting */
  keepCurrentModifiedModel?: boolean;
  /** Theme for the monaco editor */
  theme?: Theme | string;
  /** Loading component shown before editor is mounted */
  loading?: ReactNode;
  /** Diff editor construction options */
  options?: editor.IDiffEditorConstructionOptions;
  /** 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 diff editor is mounted */
  beforeMount?: DiffBeforeMount;
  /** Called when diff editor is mounted */
  onMount?: DiffOnMount;
}

Usage Examples:

import React from "react";
import { DiffEditor } from "@monaco-editor/react";

// Basic diff comparison
function BasicDiffEditor() {
  const originalCode = `function hello() {
  console.log("Hello");
}`;

  const modifiedCode = `function hello(name) {
  console.log("Hello " + name);
}`;

  return (
    <DiffEditor
      height="400px"
      language="javascript"
      original={originalCode}
      modified={modifiedCode}
    />
  );
}

// Advanced diff with custom options
function AdvancedDiffEditor() {
  const original = `const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 }
];`;

  const modified = `const users = [
  { name: "Alice", age: 25, active: true },
  { name: "Bob", age: 30, active: false },
  { name: "Charlie", age: 35, active: true }
];`;

  const options = {
    readOnly: false,
    renderSideBySide: true,
    enableSplitViewResizing: true,
    renderOverviewRuler: true,
    ignoreTrimWhitespace: false,
  };

  return (
    <DiffEditor
      height="500px"
      language="javascript"
      original={original}
      modified={modified}
      options={options}
      theme="vs-dark"
    />
  );
}

// Multi-language diff
function MultiLanguageDiff() {
  const tsCode = `interface User {
  name: string;
  age: number;
}`;

  const jsCode = `/**
 * @typedef {Object} User
 * @property {string} name
 * @property {number} age
 */`;

  return (
    <DiffEditor
      height="300px"
      originalLanguage="typescript"
      modifiedLanguage="javascript"
      original={tsCode}
      modified={jsCode}
    />
  );
}

Diff Event Handlers

Event handlers for diff editor lifecycle management.

/**
 * Called when diff editor is mounted
 * @param editor - The standalone diff editor instance
 * @param monaco - The monaco editor namespace
 */
type DiffOnMount = (editor: editor.IStandaloneDiffEditor, monaco: Monaco) => void;

/**
 * Called before diff editor is mounted
 * @param monaco - The monaco editor namespace  
 */
type DiffBeforeMount = (monaco: Monaco) => void;

type MonacoDiffEditor = editor.IStandaloneDiffEditor;

Event Handler Examples:

import { DiffEditor } from "@monaco-editor/react";

function DiffWithHandlers() {
  const handleBeforeMount = (monaco) => {
    // Configure monaco before diff editor creation
    monaco.editor.defineTheme('diffTheme', {
      base: 'vs',
      inherit: true,
      rules: [],
      colors: {
        'diffEditor.insertedTextBackground': '#90EE9050',
        'diffEditor.removedTextBackground': '#FF634750',
      }
    });
  };

  const handleMount = (diffEditor, monaco) => {
    // Access both original and modified editors
    const originalEditor = diffEditor.getOriginalEditor();
    const modifiedEditor = diffEditor.getModifiedEditor();
    
    // Configure diff editor behavior
    diffEditor.updateOptions({
      renderSideBySide: true,
      enableSplitViewResizing: true,
    });
    
    // Focus on modified editor
    modifiedEditor.focus();
    
    // Add navigation commands
    diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.DownArrow, () => {
      diffEditor.goToNextDiff();
    });
    
    diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.UpArrow, () => {
      diffEditor.goToPreviousDiff();
    });
  };

  return (
    <DiffEditor
      height="400px"
      language="javascript"
      original="const a = 1;"
      modified="const a = 2;"
      beforeMount={handleBeforeMount}
      onMount={handleMount}
      theme="diffTheme"
    />
  );
}

Diff Editor Configuration

Configuration options specific to the diff editor functionality.

// Diff editor specific options
interface DiffEditorOptions {
  /** Monaco diff editor construction options */
  options?: editor.IDiffEditorConstructionOptions;
}

// Content configuration for diff comparison
interface DiffContentProps {
  /** Original (left) content */
  original?: string;
  /** Modified (right) content */
  modified?: string;
  /** Language for both sides */
  language?: string;
  /** Separate language for original side */
  originalLanguage?: string;
  /** Separate language for modified side */
  modifiedLanguage?: string;
}

// Model paths for diff editor
interface DiffModelProps {
  /** Path/URI for original model */
  originalModelPath?: string;
  /** Path/URI for modified model */
  modifiedModelPath?: string;
  /** Keep original model when unmounting */
  keepCurrentOriginalModel?: boolean;
  /** Keep modified model when unmounting */
  keepCurrentModifiedModel?: boolean;
}

Configuration Examples:

import { DiffEditor } from "@monaco-editor/react";

// Customized diff editor
function CustomDiffEditor() {
  const diffOptions = {
    // Display options
    renderSideBySide: true,              // Side-by-side vs inline
    renderMarginRevertIcon: true,        // Show revert icons
    renderOverviewRuler: true,           // Show overview ruler
    renderIndicators: true,              // Show change indicators
    
    // Interaction options
    enableSplitViewResizing: true,       // Allow resizing split
    readOnly: false,                     // Allow editing
    originalEditable: false,             // Original side read-only
    
    // Diff algorithm options
    ignoreTrimWhitespace: true,          // Ignore whitespace at line ends
    renderWhitespace: 'selection',       // Show whitespace
    diffWordWrap: 'inherit',             // Word wrapping
    
    // Navigation
    automaticLayout: true,               // Auto-resize
    scrollBeyondLastLine: false,
  };

  return (
    <DiffEditor
      height="600px"
      width="100%"
      language="typescript"
      theme="vs-dark"
      options={diffOptions}
      original="// Original code"
      modified="// Modified code"
    />
  );
}

// File-based diff with model paths
function FileDiffEditor() {
  return (
    <DiffEditor
      height="500px"
      language="javascript"
      originalModelPath="file:///original/main.js"
      modifiedModelPath="file:///modified/main.js"
      original={`function calculate(a, b) {
  return a + b;
}`}
      modified={`function calculate(a, b) {
  // Added validation
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new Error('Arguments must be numbers');
  }
  return a + b;
}`}
      keepCurrentOriginalModel={true}
      keepCurrentModifiedModel={true}
    />
  );
}

Common Use Cases

Code Review Workflow

import React, { useState } from "react";
import { DiffEditor } from "@monaco-editor/react";

function CodeReviewDiff() {
  const [currentFile, setCurrentFile] = useState(0);
  
  const changedFiles = [
    {
      filename: "src/utils.js",
      original: `export function formatDate(date) {
  return date.toLocaleDateString();
}`,
      modified: `export function formatDate(date) {
  if (!date || !(date instanceof Date)) {
    throw new Error('Invalid date provided');
  }
  return date.toLocaleDateString();
}`
    },
    {
      filename: "src/api.js", 
      original: `async function fetchUser(id) {
  const response = await fetch(\`/api/users/\${id}\`);
  return response.json();
}`,
      modified: `async function fetchUser(id) {
  const response = await fetch(\`/api/users/\${id}\`);
  if (!response.ok) {
    throw new Error(\`Failed to fetch user: \${response.status}\`);
  }
  return response.json();
}`
    }
  ];

  return (
    <div>
      <div style={{ marginBottom: 10 }}>
        {changedFiles.map((file, index) => (
          <button 
            key={index}
            onClick={() => setCurrentFile(index)}
            style={{
              marginRight: 10,
              fontWeight: currentFile === index ? 'bold' : 'normal',
              background: currentFile === index ? '#007acc' : '#f0f0f0',
              color: currentFile === index ? 'white' : 'black',
              border: 'none',
              padding: '8px 12px',
              cursor: 'pointer'
            }}
          >
            {file.filename}
          </button>
        ))}
      </div>
      
      <DiffEditor
        height="500px"
        language="javascript"
        original={changedFiles[currentFile].original}
        modified={changedFiles[currentFile].modified}
        options={{
          renderSideBySide: true,
          renderMarginRevertIcon: false,
          readOnly: true,
        }}
      />
    </div>
  );
}

Version Comparison

function VersionComparisonDiff() {
  const [versions] = useState([
    { version: "1.0.0", code: "const API_URL = 'http://localhost';" },
    { version: "1.1.0", code: "const API_URL = process.env.API_URL || 'http://localhost';" },
    { version: "2.0.0", code: "const API_URL = process.env.REACT_APP_API_URL || 'https://api.example.com';" }
  ]);
  
  const [leftVersion, setLeftVersion] = useState(0);
  const [rightVersion, setRightVersion] = useState(1);

  return (
    <div>
      <div style={{ marginBottom: 10 }}>
        <label>Original: 
          <select value={leftVersion} onChange={(e) => setLeftVersion(+e.target.value)}>
            {versions.map((v, i) => (
              <option key={i} value={i}>{v.version}</option>
            ))}
          </select>
        </label>
        <label style={{ marginLeft: 20 }}>Modified:
          <select value={rightVersion} onChange={(e) => setRightVersion(+e.target.value)}>
            {versions.map((v, i) => (
              <option key={i} value={i}>{v.version}</option>
            ))}
          </select>
        </label>
      </div>
      
      <DiffEditor
        height="300px"
        language="javascript"
        original={versions[leftVersion].code}
        modified={versions[rightVersion].code}
      />
    </div>
  );
}

docs

diff-editor.md

editor.md

index.md

loader.md

monaco-hook.md

tile.json