Code Editor (Monaco/CodeMirror) Implementation for Website

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1215
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1043
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

Implementing Code Editor (Monaco/CodeMirror) on Website

An embedded code editor is needed in IDE tools, educational platforms, configurators, playground pages, and any SaaS where users write scripts or configurations. Connecting <textarea> is not an option: no syntax highlighting, no autocomplete, no proper indent handling.

Monaco Editor vs CodeMirror 6

Monaco Editor — VS Code in the browser. Full TypeScript autocomplete with type-checking, go-to-definition, find-all-references. Weighs ~7 MB in bundle. Justified for serious IDE-like interfaces.

CodeMirror 6 — modular, weighs from 50 KB (only what's connected). Faster initialization, better mobile support. For most use cases — the right choice.

Integrating Monaco in React

npm install @monaco-editor/react

Package loads Monaco via CDN from web worker, doesn't bloat bundle:

import Editor, { OnMount, BeforeMount } from '@monaco-editor/react'
import * as monaco from 'monaco-editor'

interface CodeEditorProps {
  value: string
  onChange: (value: string) => void
  language?: string
  readOnly?: boolean
}

export function CodeEditor({ value, onChange, language = 'typescript', readOnly = false }: CodeEditorProps) {
  const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null)

  const handleBeforeMount: BeforeMount = (monacoInstance) => {
    // Register custom language or theme before mounting
    monacoInstance.editor.defineTheme('my-dark', {
      base: 'vs-dark',
      inherit: true,
      rules: [],
      colors: {
        'editor.background': '#0f172a',
        'editor.lineHighlightBackground': '#1e293b',
      },
    })
  }

  const handleMount: OnMount = (editor, monacoInstance) => {
    editorRef.current = editor

    // TypeScript/JavaScript — configure compiler options
    monacoInstance.languages.typescript.typescriptDefaults.setCompilerOptions({
      target: monacoInstance.languages.typescript.ScriptTarget.ES2020,
      moduleResolution: monacoInstance.languages.typescript.ModuleResolutionKind.NodeJs,
      strict: true,
    })

    // Add type definitions for autocomplete
    monacoInstance.languages.typescript.typescriptDefaults.addExtraLib(
      `declare module 'my-api' { export function query(sql: string): Promise<any[]> }`,
      'file:///node_modules/my-api/index.d.ts'
    )

    // Hotkeys
    editor.addCommand(monacoInstance.KeyMod.CtrlCmd | monacoInstance.KeyCode.KeyS, () => {
      onSave?.(editor.getValue())
    })
  }

  return (
    <Editor
      height="400px"
      language={language}
      value={value}
      theme="my-dark"
      beforeMount={handleBeforeMount}
      onMount={handleMount}
      onChange={(val) => onChange(val ?? '')}
      options={{
        readOnly,
        minimap: { enabled: false },
        fontSize: 14,
        tabSize: 2,
        wordWrap: 'on',
        scrollBeyondLastLine: false,
        renderLineHighlight: 'line',
        padding: { top: 16, bottom: 16 },
      }}
    />
  )
}

Multiple Files (multi-model)

When switching between files without losing cursor position and undo-history:

function MultiFileEditor({ files }: { files: File[] }) {
  const [activeFile, setActiveFile] = useState(files[0].path)
  const modelsRef = useRef<Record<string, monaco.editor.ITextModel>>({})
  const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null)

  const handleMount: OnMount = (editor, monacoInstance) => {
    editorRef.current = editor

    // Create model for each file
    files.forEach((file) => {
      const uri = monacoInstance.Uri.parse(`file:///${file.path}`)
      modelsRef.current[file.path] = monacoInstance.editor.createModel(
        file.content,
        detectLanguage(file.path),
        uri
      )
    })

    editor.setModel(modelsRef.current[activeFile])
  }

  function switchFile(path: string) {
    setActiveFile(path)
    editorRef.current?.setModel(modelsRef.current[path])
  }

  return (
    <div>
      <div className="flex gap-1 border-b">
        {files.map((f) => (
          <button
            key={f.path}
            onClick={() => switchFile(f.path)}
            className={activeFile === f.path ? 'bg-gray-800 text-white' : ''}
          >
            {f.name}
          </button>
        ))}
      </div>
      <Editor onMount={handleMount} /* ... */ />
    </div>
  )
}

CodeMirror 6: Lighter Alternative

npm install @codemirror/view @codemirror/state @codemirror/lang-javascript \
  @codemirror/lang-python @codemirror/lang-css \
  @codemirror/theme-one-dark @codemirror/basic-setup
import { useEffect, useRef } from 'react'
import { EditorView, basicSetup } from 'codemirror'
import { javascript } from '@codemirror/lang-javascript'
import { oneDark } from '@codemirror/theme-one-dark'
import { EditorState } from '@codemirror/state'

function CodeMirrorEditor({ value, onChange }: { value: string; onChange: (v: string) => void }) {
  const containerRef = useRef<HTMLDivElement>(null)
  const viewRef = useRef<EditorView | null>(null)

  useEffect(() => {
    if (!containerRef.current) return

    const updateListener = EditorView.updateListener.of((update) => {
      if (update.docChanged) {
        onChange(update.state.doc.toString())
      }
    })

    const view = new EditorView({
      state: EditorState.create({
        doc: value,
        extensions: [
          basicSetup,
          javascript({ typescript: true }),
          oneDark,
          updateListener,
          EditorView.lineWrapping,
        ],
      }),
      parent: containerRef.current,
    })

    viewRef.current = view
    return () => view.destroy()
  }, []) // Mount once

  // Update value from outside without recreating editor
  useEffect(() => {
    const view = viewRef.current
    if (!view) return
    const current = view.state.doc.toString()
    if (current !== value) {
      view.dispatch({
        changes: { from: 0, to: current.length, insert: value },
      })
    }
  }, [value])

  return <div ref={containerRef} className="border rounded overflow-hidden" />
}

What We Do

Choose editor for task (Monaco for IDE-like, CodeMirror for compact scenarios), configure languages, theme according to project design, hotkeys, validation. If needed, connect language server over WebSocket for full IntelliSense on backend.

Timeframe: basic editor with highlighting and autocomplete — 1–2 days. Multi-file editor with LSP — 3–4 days.