Choosing a DOM rendering framework

I have been researching ProseMirror for a few weeks now and I want to use it in a new project at my office. I was able to get a strong demo with the just the framework and I think it fits very well with our needs. I have been looking at some of the offshoots as well, but for this post I am just focusing on ProseMirror.

Right now I am exploring ways to ease the developer experience when building dom components for use in the node views, plugins, etc. I found a couple solutions that seem to fit the bill nicely, SolidJS and Svelte. Both of these frameworks allow the developer to create a dom elements that are easy to pass to ProseMirror.

I was curious to see if anyone here had experience with them beyond a demo. Are there problems I am missing? Do they work at scale? See below for code examples and links to my proof of concepts. Specifically interesting are the image nodeView and the menu plugin.

Svelte

Full Demo

import ImageEditor from "./ImageEditor.svelte";
// ...

export default class ImageView {
  constructor(node, view, getPos) {
    // ...

    this.dom = document.createElement("div");

    this.imageEditor = new ImageEditor({
      target: this.dom,
      props: { src: node.attrs.src }
    });

    this.update(node);
  }

  update(node) {
    if (node.type !== this.node.type) return false;
    this.node = node;

    this.imageEditor.$set({ src: node.attrs.src });
    return true;
  }

  selectNode() {
    this.imageEditor.$set({ selected: true });
  }

  // ...
}

SolidJs

FullDemo

import { createRoot } from "solid-js";
import Menu from "./menu";
// ...

class MenuView {
  constructor(items, editorView) {
    // ...

    const onCommand = (e, command) => {
      e.preventDefault();
      editorView.focus();
      command(editorView.state, editorView.dispatch, editorView);
    };

    this.dom = createRoot(() => <Menu items={items} onCommand={onCommand} />);
  }

  // ...
}

I think both of them would work fine. I’d recommend using just vanilla JS for NodeViews if you can. Then, it it makes sense, use some framework. Svelte also has nice primitives for passing state. Maybe check out CurveNote, they used lit-element. In the big picture there are other, more annoying problems than just rendering a couple NodeViews with say Svelte.

I’m using SolidJS for node-views and finding it an excellent choice. I can’t see any downside because essentially I’m just creating normal dom elements as I would in a vanilla JS node-view. They just also happen to be reactively updated dom elements.

1 Like

BTW to handle clean-up properly, you should call the destroy callback passed to createRoot, e.g.:

view(editorView) {
  return createRoot((destroy) => {
    dom = <SolidStuff/>
    return {dom, destroy}
  })
}