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

monaco-hook.mddocs/

Monaco Hook

React hook for accessing the Monaco Editor instance and its APIs across components without needing to pass instances through props.

Capabilities

useMonaco Hook

React hook that provides access to the Monaco Editor instance once it's loaded.

/**
 * React hook for accessing the Monaco Editor instance
 * @returns Monaco instance or null if not yet loaded
 */
function useMonaco(): Monaco | null;

type Monaco = typeof monaco;

Usage Examples:

import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

// Basic Monaco instance access
function MonacoStatus() {
  const monaco = useMonaco();

  useEffect(() => {
    if (monaco) {
      console.log("Monaco Editor is ready!");
      console.log("Available languages:", monaco.languages.getLanguages());
    }
  }, [monaco]);

  return (
    <div>
      Monaco Status: {monaco ? "Loaded" : "Loading..."}
    </div>
  );
}

// Custom language configuration
function CustomLanguageSetup() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Register custom language
    monaco.languages.register({ id: 'myLang' });

    // Define language syntax
    monaco.languages.setMonarchTokensProvider('myLang', {
      tokenizer: {
        root: [
          [/\[error.*/, "custom-error"],
          [/\[notice.*/, "custom-notice"],
          [/\[info.*/, "custom-info"],
          [/\[[a-zA-Z 0-9:]+\]/, "custom-date"],
        ]
      }
    });

    // Configure language features
    monaco.languages.setLanguageConfiguration('myLang', {
      brackets: [
        ['[', ']'],
        ['(', ')'],
        ['{', '}']
      ],
      autoClosingPairs: [
        { open: '[', close: ']' },
        { open: '(', close: ')' },
        { open: '{', close: '}' },
      ]
    });

  }, [monaco]);

  return <div>Custom language configured</div>;
}

Theme Management

Use the Monaco instance to define and manage custom themes across your application.

// Theme definition interface (from Monaco Editor)
interface ThemeDefinition {
  base: 'vs' | 'vs-dark' | 'hc-black';
  inherit: boolean;
  rules: TokenThemeRule[];
  colors: { [colorId: string]: string };
}

interface TokenThemeRule {
  token: string;
  foreground?: string;
  background?: string;
  fontStyle?: string;
}

Theme Examples:

import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

function ThemeManager() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Define custom dark theme
    monaco.editor.defineTheme('customDark', {
      base: 'vs-dark',
      inherit: true,
      rules: [
        { token: 'comment', foreground: '6A9955', fontStyle: 'italic' },
        { token: 'keyword', foreground: '569CD6', fontStyle: 'bold' },
        { token: 'string', foreground: 'CE9178' },
        { token: 'number', foreground: 'B5CEA8' },
      ],
      colors: {
        'editor.background': '#1e1e1e',
        'editor.foreground': '#d4d4d4',
        'editorLineNumber.foreground': '#858585',
        'editorCursor.foreground': '#ffffff',
        'editor.selectionBackground': '#264f78',
        'editor.lineHighlightBackground': '#2d2d30',
      }
    });

    // Define custom light theme
    monaco.editor.defineTheme('customLight', {
      base: 'vs',
      inherit: true,
      rules: [
        { token: 'comment', foreground: '008000', fontStyle: 'italic' },
        { token: 'keyword', foreground: '0000ff', fontStyle: 'bold' },
        { token: 'string', foreground: 'a31515' },
        { token: 'number', foreground: '098658' },
      ],
      colors: {
        'editor.background': '#ffffff',
        'editor.foreground': '#000000',
        'editorLineNumber.foreground': '#237893',
        'editor.selectionBackground': '#add6ff',
        'editor.lineHighlightBackground': '#f0f0f0',
      }
    });

  }, [monaco]);

  const applyTheme = (themeName) => {
    if (monaco) {
      monaco.editor.setTheme(themeName);
    }
  };

  return (
    <div>
      <button onClick={() => applyTheme('customDark')}>Dark Theme</button>
      <button onClick={() => applyTheme('customLight')}>Light Theme</button>
      <button onClick={() => applyTheme('vs-dark')}>VS Dark</button>
      <button onClick={() => applyTheme('vs')}>VS Light</button>
    </div>
  );
}

Language Service Configuration

Configure TypeScript/JavaScript language services and other language features.

// Language service configuration interfaces (from Monaco Editor)
interface LanguageServiceDefaults {
  setCompilerOptions(options: CompilerOptions): void;
  setDiagnosticsOptions(options: DiagnosticsOptions): void;
  addExtraLib(content: string, filePath?: string): void;
  setEagerModelSync(value: boolean): void;
}

Language Service Examples:

import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

function TypeScriptConfiguration() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Configure TypeScript compiler options
    monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
      target: monaco.languages.typescript.ScriptTarget.ES2020,
      allowNonTsExtensions: true,
      moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
      module: monaco.languages.typescript.ModuleKind.CommonJS,
      noEmit: true,
      esModuleInterop: true,
      jsx: monaco.languages.typescript.JsxEmit.React,
      reactNamespace: "React",
      allowJs: true,
      typeRoots: ["node_modules/@types"]
    });

    // Configure diagnostics
    monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
      noSemanticValidation: false,
      noSyntaxValidation: false,
      noSuggestionDiagnostics: false
    });

    // Add type definitions
    const reactTypes = `
      declare module "react" {
        export interface FC<P = {}> {
          (props: P & { children?: ReactNode }): ReactElement | null;
        }
        export type ReactNode = ReactElement | string | number | boolean | null | undefined;
        export interface ReactElement<P = any> {
          type: string | FC<P>;
          props: P;
          key: string | number | null;
        }
      }
    `;

    monaco.languages.typescript.typescriptDefaults.addExtraLib(
      reactTypes,
      'file:///node_modules/@types/react/index.d.ts'
    );

    // Enable eager model sync for better performance
    monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);

  }, [monaco]);

  return <div>TypeScript language service configured</div>;
}

function CustomCompletionProvider() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Register custom completion provider
    const disposable = monaco.languages.registerCompletionItemProvider('javascript', {
      provideCompletionItems: (model, position) => {
        const suggestions = [
          {
            label: 'console.log',
            kind: monaco.languages.CompletionItemKind.Function,
            documentation: 'Log a message to the console',
            insertText: 'console.log($1);',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            range: {
              startLineNumber: position.lineNumber,
              endLineNumber: position.lineNumber,
              startColumn: position.column,
              endColumn: position.column
            }
          },
          {
            label: 'async function',
            kind: monaco.languages.CompletionItemKind.Snippet,
            documentation: 'Create an async function',
            insertText: 'async function ${1:functionName}(${2:params}) {\n\t$0\n}',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            range: {
              startLineNumber: position.lineNumber,
              endLineNumber: position.lineNumber,
              startColumn: position.column,
              endColumn: position.column
            }
          }
        ];

        return { suggestions };
      }
    });

    // Cleanup on unmount
    return () => disposable.dispose();
  }, [monaco]);

  return <div>Custom completion provider registered</div>;
}

Global Monaco Configuration

Configure Monaco Editor settings that apply to all editor instances.

// Global configuration options
interface GlobalMonacoConfig {
  /** Configure default options for all editors */
  setGlobalOptions(options: editor.IEditorOptions): void;
  /** Register global commands */
  addGlobalCommand(keybinding: number, handler: () => void): void;
  /** Configure language features globally */
  configureLanguageGlobally(languageId: string, config: any): void;
}

Global Configuration Examples:

import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

function GlobalMonacoSetup() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Set global editor defaults
    monaco.editor.EditorOptions.fontSize.defaultValue = 14;
    monaco.editor.EditorOptions.fontFamily.defaultValue = 'Monaco, Menlo, monospace';
    monaco.editor.EditorOptions.lineHeight.defaultValue = 1.6;

    // Configure global key bindings
    const formatAction = {
      id: 'format-document',
      label: 'Format Document', 
      keybindings: [monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.KeyF],
      run: (editor) => {
        editor.getAction('editor.action.formatDocument').run();
      }
    };

    // Register global actions
    monaco.editor.addEditorAction(formatAction);

    // Configure language defaults
    const jsDefaults = monaco.languages.typescript.javascriptDefaults;
    jsDefaults.setCompilerOptions({
      allowNonTsExtensions: true,
      allowJs: true
    });

  }, [monaco]);

  return <div>Global Monaco configuration applied</div>;
}

Integration Patterns

Provider Pattern

Create a Monaco context provider for app-wide access.

import React, { createContext, useContext, useEffect, useState } from "react";
import { useMonaco } from "@monaco-editor/react";

const MonacoContext = createContext(null);

export function MonacoProvider({ children }) {
  const monaco = useMonaco();
  const [isConfigured, setIsConfigured] = useState(false);

  useEffect(() => {
    if (!monaco || isConfigured) return;

    // Apply global configuration
    monaco.editor.defineTheme('appTheme', {
      base: 'vs-dark',
      inherit: true,
      rules: [],
      colors: {
        'editor.background': '#1a1a1a',
      }
    });

    setIsConfigured(true);
  }, [monaco, isConfigured]);

  return (
    <MonacoContext.Provider value={{ monaco, isConfigured }}>
      {children}
    </MonacoContext.Provider>
  );
}

export function useAppMonaco() {
  const context = useContext(MonacoContext);
  if (!context) {
    throw new Error('useAppMonaco must be used within MonacoProvider');
  }
  return context;
}

Conditional Rendering

Only render Monaco-dependent components after Monaco is loaded.

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

function ConditionalEditor() {
  const monaco = useMonaco();

  if (!monaco) {
    return <div>Loading Monaco Editor...</div>;
  }

  return (
    <div>
      <Editor
        height="400px"
        language="javascript"
        defaultValue="// Monaco is ready!"
      />
    </div>
  );
}

docs

diff-editor.md

editor.md

index.md

loader.md

monaco-hook.md

tile.json