Broken setSelection after setBlockType in one transaction

Hi, unfortunately I haven’t find similar topic and have to create a new one.

I create an input rule which transforms ###+space into a header of level 3 and use standard textblockTypeInputRule for this task (ProseMirror Reference manual).

The unexpected issue is that cursor is always set after the header. I created my own input rule to workaround the issue where I tried to use tr.setSelection(...) to put cursor into the converted header.

But I failed. My investigation shows that setSelection can set cursor before or after the header but NOT INSIDE it for some reason.

NOTE: after transaction is applied - I can set selection as expected.

So my guess is that setSelection doesn’t work correctly when used in one transaction with .setBlockType(...)

Here is my inputRule for reference:

const isSetSelectionBugFixed = false;
const fixedTextblockTypeInputRule = isSetSelectionBugFixed
  ? textblockTypeInputRule
  : (regexp: RegExp, nodeType: NodeType, getAttrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null)) => {
      return new InputRule(regexp, (state, match, start, end) => {
        const $start = state.doc.resolve(start);
        const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
        if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) {
          return null;

        let tr =;
        tr = tr.delete(start, end);
        tr = tr.setBlockType(start, start, nodeType, attrs);
        const selection = new TextSelection(state.doc.resolve(start)); // nor (start) nor (start + 1) nor (start - 1) doesn't work as expected
        tr = tr.setSelection(selection);
        return tr;


function headingRule(nodeType: NodeType, maxLevel: number) {
  return fixedTextblockTypeInputRule(new RegExp("^(#{1," + maxLevel + "})\\s$"), nodeType, function (match) {
    return {level: match[1].length};

Can you please confirm my assumption or point me somewhere if I do / understand something wrong.

Thank you in advance

This is exactly the same use of textblockTypeInputRule as used in the example setup, and that (see for example the demos on the website) does not have the cursor position issue. Is there something about your schema that might be causing this?

Oh, you right. Nodes are wrapped with NodeView to react components. The root cause of the issue was upgrade to the latest react and unexpected asynchrony in react portals. At the moment of setSelection(…) call - there were no rendered node in the DOM. Thank you for help and sorry for disturbing.