prosemirror-codemirror-block: CodeMirror 6 code block for ProseMirror

ProseMirrorCodeMirrorCode BlockPlugin Development
By Viktor
Wednesday, February 2, 2022

What's this about?

Release ProseMirror codeblock plugin that uses the brand-new CodeMirror 6, a major improvement over CodeMirror 5.

With:

  • Customizable language selector
  • lazy-loaded language support
  • works with YJS history

The code for this post is here

How to use?

  1. Install the plugin: npm i -S prosemirror-codemirror-block
  2. Import defaultSettings from the plugin ( and modify it if you want )
  3. Update the code_block node in the ProseMirror schema to have a lang attribute
  4. Initialize the editor with the plugin & insert keymaps for correct cursor handling around code_block

In codespeak:

1import { schema } from "prosemirror-schema-basic";
2import { EditorState } from "prosemirror-state";
3import { EditorView } from "prosemirror-view";
4import { exampleSetup } from "prosemirror-example-setup";
5import {
6    codeMirrorBlockPlugin,
7    defaultSettings,
8    languageLoaders,
9    codeBlockArrowHandlers,
10    legacyLanguageLoaders,
11} from "prosemirror-codemirror-block";
12import { undo, redo } from "prosemirror-history";
13
14
15const codeBlockSpec = schema.spec.nodes.get("code_block");
16
17export default new Schema({
18    nodes: schema.spec.nodes.update("code_block", {
19        ...(codeBlockSpec || {}),
20        attrs: { ...codeBlockSpec?.attrs, lang: { default: null } },
21    }),
22    marks: schema.spec.marks,
23});
24
25
26const codeBlockDoc = {
27    content: [
28        {
29            content: [
30                {
31                    text: "prosemirror-codemirror-block",
32                    type: "text",
33                },
34            ],
35            type: "paragraph",
36        },
37        {
38            content: [
39                {
40                    text: "const jsFun = (arg) => {\n  console.log(arg); \n}",
41                    type: "text",
42                },
43            ],
44            attrs: {
45                lang: "javascript",
46            },
47            type: "code_block",
48        },
49    ],
50    type: "doc",
51};
52
53
54const state = EditorState.create<typeof schema>({
55    doc: schema.nodeFromJSON(codeBlockDoc),
56    plugins: [
57        ...exampleSetup({
58            schema,
59        }),
60        codeMirrorBlockPlugin({
61            ...defaultSettings,
62            languageLoaders: { ...languageLoaders, ...legacyLanguageLoaders },
63            undo,
64            redo,
65        }),
66        keymap(codeBlockArrowHandlers),
67    ],
68});
69
70const view: EditorView = new EditorView(document.getElementById("editor"), {
71  state,
72});

You might also want to add

1.codeblock-select {
2    position: absolute;
3    right: 0;
4    z-index: 100;
5    opacity: 0;
6    transition: all 0.3s ease;
7    margin: 6px 14px;
8}
9.codeblock-root {
10    position: relative;
11}
12
13.codeblock-root:hover .codeblock-select {
14    opacity: 1;
15}

to the editor style in order to have a nicely positioned language selector.

Now....You have a better code_block, and the world just got a bit better.

You can check out the docs at https://gitlab.com/emergence-engineering/prosemirror-codemirror-block

Let’s talk

Building something hard?

If your product lives or dies on the editor, the collaboration, or getting something impossible to run in the browser, that’s exactly the conversation we like.

No sales pitch. Just an honest read on whether we’re the right team for your problem.