Examples

React

The editor inside a React component: mounted in useEffect, destroyed on unmount, its text held in React state so the rest of the app can read and replace it. It uses the plain API; there is no React wrapper to install.

import { useEffect, useRef, useState } from "react";
import { createRoot } from "react-dom/client";
import { createEditorState, mountEditor, type MarkdownEditor } from "@openmarkdown-dev/editor";

const INITIAL = "# Notes\n\nThis editor lives in a React component.\nType here and watch the counter below.\n";

/** Mounts once, destroys on unmount; `value` from outside replaces the document. */
function Editor({ value, onChange }: { value: string; onChange: (doc: string) => void }) {
  const el = useRef<HTMLDivElement>(null);
  const editor = useRef<MarkdownEditor | null>(null);
  const latest = useRef(onChange);
  latest.current = onChange;

  useEffect(() => {
    const ed = mountEditor(el.current!, createEditorState({ doc: value, host: { onChange: (doc) => latest.current(doc) } }));
    editor.current = ed;
    return () => {
      ed.destroy();
      editor.current = null;
    };
  }, []); // mount once; later values arrive through the effect below

  useEffect(() => {
    const ed = editor.current;
    if (ed && ed.getDoc() !== value) ed.setDoc(value);
  }, [value]);

  return <div ref={el} className="editor" />;
}

function App() {
  const [doc, setDoc] = useState(INITIAL);
  return (
    <>
      <Editor value={doc} onChange={setDoc} />
      <div className="bar">
        <button type="button" onClick={() => setDoc(INITIAL)}>Reset</button>
        <output id="count">{doc.length} characters</output>
      </div>
    </>
  );
}

createRoot(document.getElementById("root")!).render(<App />);
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>OpenMarkdown editor: React</title>
    <style>
      #root .editor { height: 340px; border: 1px solid #d9d6cf; border-radius: 8px; overflow: hidden; }
      #root .editor .cm-editor { height: 100%; }
      #root .bar { display: flex; gap: 12px; align-items: center; margin-top: 10px; font: 14px system-ui, sans-serif; }
    </style>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="./main.tsx"></script>
  </body>
</html>
{
  "name": "openmarkdown-editor-example-react",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@openmarkdown-dev/editor": "0.1.0",
    "react": "^19.1.0",
    "react-dom": "^19.1.0"
  },
  "devDependencies": {
    "typescript": "~5.8.3",
    "vite": "^7.0.4",
    "@types/react": "^19.1.8",
    "@types/react-dom": "^19.1.6"
  }
}