Prosemirror table manipulation via yjs

I’m trying to manually change yjs content to perform table cells merging in prosemirror table. The content consists of a XmlFragment of structure:

XmlFragment (root)
  XmlElement (table)
    XmlElement (tableRow)
      XmlElement (tableCell)
        XmlElement (paragraph)
          XmlText (text content)

There are two identical tables with the same structure but different data inside table cells. I need to do the same actions to another table, like cells merging. I use deep observer for local table which observes events and makes modifications to an alternative table. Simplified example:

yFragment.observeDeep((yxmlEvents, transaction) => {
  if (!transaction.local) return;

  transaction.doc.transact(() => {
    yxmlEvents.forEach((yxmlEvent) => {
      const { path, delta, target, changes } = yxmlEvent;
      const elementPath = path as number[];
      const flattenChanges = Object.assign({},;
      // getNodeNames returns a list of nodes
      const deletedNodes = getNodeNames(changes.deleted);
      // getYElementByPath finds same element in alternative table by path.
      const yAltElementByPath = getYElementByPath(yAltFragment, elementPath);
      changes.keys.forEach((change, key) => {
        const newValue = target.getAttribute(key);
        if (change.action === "update" && newValue) {
          yAltElementByPath.setAttribute(key, newValue);
      if (deletedNodes.includes("tableCell")) && flattenChanges.delete) {
        yAltElementByPath.delete(flattenChanges.retain || 0, flattenChanges.delete);

This is one of variants I have used to do updates, there were numerous, like cloning XmlElements and its content, converting yjs fragment to prosemirror nodes, json manipulation and inserting result. The same problem comes after: alternative table inserts additional cells in each row causing additional column appearance! I thought this is because I change rowspan attribute and then delete cells as a separate action, but I believed transaction.doc.transact should resolve it. I tried to remove rows and reinsert them cloned and modified — same result. Replacing whole table also does not help.

What am I doing wrong?

Update: this happens only when prosemirror editor of alternative table is opened in browser. Checking transaction shows that meta has fixTables so this is why it is happening. Still don’t have a clue about a workaround.

Making changes and only after that opening editor in a browser shows correct table structure.

For now I’ve made a workaround which postpones fixTable in filterTransaction on Prosemirror side:

const pluginKey = new PluginKey("postponeFixTable");
const plugin = new Plugin({
  key: pluginKey,
  state: {
    init() {
      return { fixTables: false };
    apply(tr, state) {
      return state;
  filterTransaction: (tr, state) => {
    const pluginState = pluginKey.getState(state);
      const metaFixTable = tr.getMeta("fix-tables$");

      if (metaFixTable?.fixTables) {
        pluginState.fixTables = true;
        return false;
      } else if (pluginState.fixTables) {
        pluginState.fixTables = false;
      return true;

But I’m worried about side-effects.