How to get HTML of an editor including custom Node Views

I have an editor with plenty of extensions with some custom Node Views. I want to get the HTML of my content to simply put it on my page and store it in Database to retrieve the document when someone would like to edit content. I’m using tiptap and their editor.getHTML() which uses DOMSerializer. The problem is that it returns the HTML code which doesnt take into account custom Node Views. Should I use view.dom.innerHTML instead? The problem with it, at least for now is that it doesnt work properly with my custom math nodes (inline and display). I could store both JSON of my ProseMirror editor (for editing purposes) and HTML of my editor (for displaying purposes) but I would like to store just one information.

No, definitely not. You could define a custom DOMSerializer that renders your nodes the way you want (possibly sharing code with your node views, though often, the interactive elements used for in-editor node views don’t match what these nodes should be rendered as in static HTML).

Why can’t I use view.dom.innerHTML? Of course it has elements which are needed only for in-editor editing but I can always don’t render these elements when editor is in editable: false mode.

By defining custom DOMSerializer you mean that I should make my toDOM method in line with my Node View? That means that the parseDOM should also be changed to match toDOM right?

You don’t necessarily need to use the toDOM from the schema—you can also use new DOMSerializer to create a serializer with custom serializer functions (you’ll usually want to use one from a schema as a base, so you don’t have to redefine every node).

1 Like

OK but I still don’t get why can I use view.dom.innerHTML. If there is no custom node views, it should be the same as the one from serializer.

I did the following:


	parseHTML() {
		return [
			{
				tag: "span.math-src",
			},
		];
	},

	renderHTML({ HTMLAttributes, node }) {
		let dom = document.createElement("math-inline");
		dom.className = "math-node";

		let tex = node.textContent;
		let src = document.createElement("span");
		src.className = "math-src";
		src.innerText = tex;

		let render = document.createElement("span");
		render.className = "math-render";

		katex.render(tex, render, {
			displayMode: false,
			globalGroup: true,
		});

		dom.appendChild(src);
		dom.appendChild(render);

		return dom;
}

In short, in static html I want to have a child span.math-src which contains raw latex text, and span.math-render which contains rendered html. When parsing a node, all I need is a content of span.math-src. The prolem is that with the current parse rule, the stuff from span.math-render is also parsed and two more apragraph are added (outside of the math-inline node). What should I change to skip parsing of span.math-render dom node?

EDIT Solved by adding

	parseHTML() {
		return [
			{
				tag: "math-inline",
				contentElement: ".math-src",
			},
		];
	},

Is it the correct way? And how to add event listeners to the static HTML?

No idea what parseHTML/renderHTML are here, but if that is passed through to parseDOM I guess this works. You could also use a getContent property to completely override the way the content is parsed, but I don’t think that is better in this case.

OK s othe very last question is how to add event listeners to the static HTML. I have spoiler element and I want to reveal it after clicking on it. I have

renderHTML({ HTMLAttributes }) {
		let dom = document.createElement("spoiler");
		dom.className = "spoiler";
		dom.dataset.spoiler = "reveal-spoiler";
		dom.addEventListener("click", () => {
			console.log("Hi");
			if (!dom.classList.contains("is-visible")) {
				dom.classList.add("is-visible");
			}
		});


		dom.onclick = () => {
			if (!dom.classList.contains("is-visible")) {
				dom.classList.add("is-visible");
			}
		};

                // Option 2
		let contentDOM = document.createElement("div");
		dom.appendChild(contentDOM);

		return {
			dom,
			contentDOM,
		};

		return [
			"spoiler",
			mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
			0,
		];
	},

But it works only in editing mode. If I use editor.getHTML() and display it, nothing happens after click. (renderHTML is Tiptap’s equivalent of toDOM)