Reacting to node join

I have a case with a custom bullet point list where each item has a score.

I need to add scores when two items are joined. For example, when the user hits Backspace at the beginning of a line, the resulting item’s score would be the addition of the two item’s score.

I did a quick hack to showcase the idea by overriding Transform.prototype.join but I am wondering what would be the correct way to do it.

My first thought is to write my own Backspace command on the custom node, but there’s a lot of code to copy/paste just to change the way join works. And it would not cover other join scenarios like hitting Delete at the end of a line, etc.

Is it possible to have a custom join defined for a custom node ?

Thanks for your help or any hint !

Yes—write a more specific version of the join command that only fires in your case, and bind it before the default join comment.


I know how to bind a custom command to a key but the join I wabt to customize is a transform method.

How can I achieve the binding of a transform method? Is it in the node with something like:

export default class TodoItem extends Node {

  get name() {
    return 'todo_item'

  transforms() {
    join: myCustomJoin()

Hi @marijn,

Still not sure how to bind a transform method.

Is there another way to have the join transform specific to a node ?

I was referring to key bindings. You can’t bind transform methods, but you can create more specific versions of commands and bind them to the same key but with higher precedence.

OK! Thanks for your feedback. I will work with key binding as you suggested.

Just want to say I had a similar problem with nested blocks. I needed to overwrite any deletions, or deletion + inserts because they were often not what I wanted. I tried a custom command bound to backspace but this will misses things like pasting when a selection spans multiple nodes, dragging, creating a selection then hitting a key to insert text, etc. Just saw this and thought you might want to know.

I tried several things and ended up creating a plugin that uses filterTransaction to prevent any transactions that would delete ranges prosemirror would otherwise delete strangely and dispatches a new correct one. Kind of hacky and it has a few limitations but it seemed simpler than trying to rewrite how deletions work and it’s working pretty well.

Thanks for your experience feedback @alannorth !

I will let you know what I ended up with.

1 Like