# How to use CodeMirror in JupyterLab Extension

**URL:** <https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630>\
**Category:** extensions\
**Tags:** how-to, help-wanted\
**Created:** [August 16, 2024, 7:30am UTC](https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630 "2024-08-16T07:30:28Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ThibautDR](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/thibautdr/32/13005_2.png) [@ThibautDR](https://discourse.jupyter.org/u/ThibautDR)\
**Post date:** [August 16, 2024, 7:30am UTC](https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630/1 "2024-08-16T07:30:28Z")

</div>

Hello everyone,

I’m trying to play around and use the native Jupyterlab CodeEditor in my extension.  
However I struggle with what I believe a change in the API with the 4.0 and can’t find examples to help me.

For example [this extension](https://github.com/jupytercalpoly/jupyterlab-code-snippets/blob/24ea8a6908c8fdc61cd4e500b804291a47ab7e3f/src/CodeSnippetEditor.tsx#L292) uses the CodeEditor but for JLAB v3. My problem is with the value. It looks like we could set the value of the text in the code editor with model.value but it seems to not be the case now.

Here is the code I have for now:

```auto
export const CodeTextarea: React.FC<CodeTextareaProps> = ({
  field,
  value,
  handleChange,
  advanced,
}) => {
  const editorRef = useRef<HTMLDivElement | null>(null);
  const [editor, setEditor] = useState<CodeEditor.IEditor | null>(null);

  useEffect(() => {
    if (editorRef.current) {
      const languages = new EditorLanguageRegistry();
      const factory = new CodeMirrorEditorFactory({
        extensions: new EditorExtensionRegistry(),
        languages
      });

      const model = new CodeEditor.Model({
        mimeType: 'text/x-python',
      });

      const editor = factory.newInlineEditor({
        host: editorRef.current,
        model: model,
        config: {
          value: value,
          mode: 'text/x-python',
          lineNumbers: true
        }
      });

      setEditor(editor);

      return () => {
        editor.dispose();
      };
    }
  }, [value]);

  useEffect(() => {
    if (editor) {
      editor.model.value.changed.connect((sender, args) => {
        handleChange(editor.model.value.text, field.id);
      });
    }
  }, [editor, handleChange, field.id]);

  return (
    <div ref={editorRef} style={{ height: '300px', width: '100%' }} />
  );
};

```

Errors are with:

```auto
      editor.model.value.changed.connect((sender, args) => {
        handleChange(editor.model.value.text, field.id);
      });
    }

```

because:

> Property ‘value’ does not exist on type ‘IModel’.ts(2339)

Of course, I checked the [reference API](https://jupyterlab.readthedocs.io/en/stable/api/interfaces/codeeditor.CodeEditor.IModel.html), but don’t necessarily understand the documentation.

Any pointers on what I’m missing would be really appreciated, thanks in advance 🙏

Thibaut

---

<div class="post-metadata">

**Author:** ![krassowski](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/krassowski/32/1685_2.png) [@krassowski](https://discourse.jupyter.org/u/krassowski)\
**Post date:** [August 16, 2024, 9:06am UTC](https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630/2 "2024-08-16T09:06:27Z")

</div>

Maybe something along the lines of `editor.model.sharedModel.getSource()`?

Related to [Document how to set text on CodeEditor in JupyterLab 4.0 · Issue #13427 · jupyterlab/jupyterlab · GitHub](https://github.com/jupyterlab/jupyterlab/issues/13427)

---

<div class="post-metadata">

**Author:** ![krassowski](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/krassowski/32/1685_2.png) [@krassowski](https://discourse.jupyter.org/u/krassowski)\
**Post date:** [August 16, 2024, 9:09am UTC](https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630/3 "2024-08-16T09:09:32Z")

</div>

As for how to get there from API reference, the link you posted has `sharedModel`:

> **[IModel | @jupyterlab](https://jupyterlab.readthedocs.io/en/stable/api/interfaces/codeeditor.CodeEditor.IModel.html#sharedModel)**
>
> Documentation for @jupyterlab

which links to `ISharedText`:

> **[ISharedText | @jupyter/ydoc](https://jupyter-ydoc.readthedocs.io/en/latest/api/interfaces/ISharedText.html)**
>
> Documentation for @jupyter/ydoc

which has a `source` attribute and `getSource()` method. It seems to me that these two are redundant as `source` getter just calls `getSource()`

---

<div class="post-metadata">

**Author:** ![ThibautDR](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/thibautdr/32/13005_2.png) [@ThibautDR](https://discourse.jupyter.org/u/ThibautDR)\
**Post date:** [August 17, 2024, 7:12am UTC](https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630/4 "2024-08-17T07:12:20Z")

</div>

Thanks @krassowski, that was it. Thanks for the references, I actually saw it in the doc but didn’t understand it was value’s replacement.

Now, there is still something I didn’t get:

```auto
    if (editorRef.current && !editorInstanceRef.current) {
      const model = new CodeEditor.Model();
      const options: CodeEditor.IOptions = {
        host: editorRef.current,
        model,
        config: {
          lineHeight: 4,
        },
      };

      const codeEditor = new CodeMirrorEditor(options);
      editorInstanceRef.current = codeEditor;

      // Handle changes from the editor
      codeEditor.model.sharedModel.changed.connect(() => {
        const newValue = codeEditor.model.sharedModel.getSource();
        handleChange(newValue, field.id);
      });

```

I thought that typing text in the CodeEditor would trigger codeEditor.model.sharedModel.changed so that I could capture the value. However, it seems that is not the case. the sharedModel is the value that is saved, but how to get the value that is typed in the CodeEditor?

Thanks you,  
Thibaut

---

<div class="post-metadata">

**Author:** ![krassowski](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/krassowski/32/1685_2.png) [@krassowski](https://discourse.jupyter.org/u/krassowski)\
**Post date:** [August 18, 2024, 2:13pm UTC](https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630/5 "2024-08-18T14:13:04Z")

</div>

Your `CodeMirrorEditor` is missing `ybinding` so the model updates will indeed not get propagated correctly, for an example see:

> <https://github.com/jupyterlab/jupyterlab/blob/35bab6e06d8e4f347219f91a4f0315a4169dfe09/packages/completer/src/testutils.ts#L13-L21>

But if you do not want to setup the shared model for some reason you could possibly use the direct access to `codeEditor.doc().toString()`?

- [CodeMirrorEditor | @jupyterlab](https://jupyterlab.readthedocs.io/en/latest/api/classes/codemirror.CodeMirrorEditor-1.html#doc)
- [CodeMirror Reference Manual](https://codemirror.net/docs/ref/#state.Text)

---

<div class="post-metadata">

**Author:** ![ThibautDR](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/thibautdr/32/13005_2.png) [@ThibautDR](https://discourse.jupyter.org/u/ThibautDR)\
**Post date:** [August 19, 2024, 9:53pm UTC](https://discourse.jupyter.org/t/how-to-use-codemirror-in-jupyterlab-extension/27630/6 "2024-08-19T21:53:17Z")

</div>

Thanks a lot @krassowski. Binding the model to the editor was the key indeed 🙂

Haven’t tried the direct access because I needed to be able to detect changes and found the observe method (which might be possible with direct access idk but only found the solution with the sharedModel):

```auto
      sharedModel.ysource.observe(() => {
        const newValue = sharedModel.ysource.toString();
        if (newValue !== value) {
          handleChange(newValue, field.id);
        }
      });

```
