prosemirror Text Alignment

First import the classes you need to modify

import { Textblock, Heading, Paragraph, Attribute, Block } from "prosemirror/dist/model"

Add the new attribute to Textblock. We only wanted alignment for text, if you want it for everything probably best to do this on Block

	align: new Attribute({default: "left"})

Because heading has it’s own get attrs() we need to add it there also

	align: new Attribute({default: "left"})

Now we need to represent this attribute in the DOM, this is done with to to_dom transform, which defers to the serializeDOM method of a node type

Paragraph.prototype.serializeDOM = (function(oldSerialize) {
    return function (node, s) {
	let ele =, node, s)
	this.setDomDisplayProperties(node, ele) //will be explained next
	return ele
}) (Paragraph.prototype.serializeDOM)

This maintains the old serialize implementation, but adds some additional functionality. You’ll need to do this to every NodeType that needs alignment. Since each NoteType defines its own, I haven’t found a good way to make it fully reusable. I did crate the setDomDisplayProperties method to handle actually adding the change to the DOM element, which is reuseable

Textblock.prototype.setDomDisplayProperties = function setDomDisplayProperties(node, ele) { = node.attrs.align

So now it should render! Like I mentioned serializeDOM has to be changed for all NodeTypes, here’s heading’s for good measure:

Heading.prototype.serializeDOM = (function(oldSerialize) {
    return function serializeDOM(node, s) {
	let ele =,node, s)
	this.setDomDisplayProperties(node, ele)
	return ele
}) (Heading.prototype.serializeDOM)

One final thing we need to do is make sure it works the other way, from_dom, which comes into play when copy and pasting or with drag and drop.

First we register a new parser. By default they have a rank of 50, so we give ours a lower rank to make sure it matches first

export function fromHTMLBlock(dom, state) {
	state.wrapIn(dom, this, this.deserializeDOMAttrs(dom))

Paragraph.register('parseDOM', 'p', {
	parse: fromHTMLBlock,
	rank: 40

fromHTMLDOM is pretty much the same as the ‘block’ parser but calls this.deserializeDOMAttrs(dom) to add the attributes as well.

Textblock.prototype.deserializeDOMAttrs = function deserializeDOMAttrs(dom) {
	let attrs = {}
	attrs.align = || "left"
	return attrs

This will be inherited by all textblocks, but they can define their own or add to the returned value in a different parse funtion, if they have additional properties. Heading, for example:

for (let i = 1; i <= 6; i++) Heading.registerComputed("parseDOM", "h" + i, type => {
  if (i <= type.maxLevel) return {
    parse: function(dom, state) {
      let attrs = this.deserializeDOMAttrs(dom)
      attrs.level = i
      state.wrapIn(dom, this, attrs)
    rank: 40

I think that about covers it, hope this helped!

About Reza Ervani 430 Articles
Adalah pendiri -

Be the first to comment

Leave a Reply

Your email address will not be published.


This site uses Akismet to reduce spam. Learn how your comment data is processed.