Wired behavior on adding custom node with node view

i created custom node to represent variable as chip.

export class VariableNodeView {
    outerView;
    dom;
    constructor(private node, private view, private getPos) {
        // We'll need these later
        this.node = node;
        this.outerView = view;
        this.getPos = getPos;
        this.buildVariable();
    }

    buildVariable() {
        this.dom = document.createElement("span");
        this.dom.setAttribute('style', 'border:solid 1px;border-radius: 4px;background-color: #e8f0fe;padding:2px 5px;font-size: 16px; padding: 2px 5px; color: #1a73e8;');
        this.setAttrs()
    }

    setAttrs() {
        const {attrs} = this.node;
        this.dom.innerHTML = attrs.label;
        for(const k in attrs) {
            this.dom.setAttribute(k, attrs[k]);
        }
    }


    selectNode() {
        console.log('selectNode', this.node);
        this.dom.classList.add("variable-selected")
        // if (!this.innerView) this.open()
    }

    deselectNode() {
        console.log('deselectNode')
        this.dom.classList.remove("ProseMirror-selectednode")
    }
    open() {
        console.log('open');
        // Append a tooltip to the outer node
        let tooltip = this.dom.appendChild(document.createElement("div"))
        tooltip.className = "footnote-tooltip"
        // And put a sub-ProseMirror into that
    }

    close() {
        this.dom.textContent = ""
    }
    update(node) {
       this.node = node;
       this.setAttrs();
        return true
    }
    destroy() {
        console.log('destroy');
    }

    stopEvent(event) {
        console.log('stopEvent', this.dom && this.dom.contains(event.target));
        return !this.dom && this.dom.contains(event.target);
    }

    ignoreMutation() { return true }
}

export const VariableNodeViewFn = (node, view, getPos) => new VariableNodeView(node, view, getPos);



//SCHEMA

export const VariableNodeSpec: any = {
    attrs: {type: {default: 'variable'}, label: {default: ''}, key: {default: ''}, value: {default: {}} },
    inline: true,
    group: "inline",
    draggable: true,
    // These nodes are rendered as images with a `dino-type` attribute.
    // There are pictures for all dino types under /img/dino/.
    toDOM: (node) => {
        const properties: any = Object.assign({}, node.attrs.label, {'data-type': 'variable'});
        return ['span', properties, 0];
    },
    // When parsing, such an image, if its type matches one of the known
    // types, is converted to a dino node.
    parseDOM: [{
        tag: "span[type-variable]",
    }]
}

i am getting wired behavior after adding new variable node with command

dispatch(state.tr.replaceSelectionWith(schema.nodes.variable.create(attrs)));

in the current example i tried to create variable node inside h1 node. how can i move the cursor after the new node i added. currently its not letting me to type and it tries to create another variable node.

after adding the new node, any keyboard type cause a wired behavior of adding another span with color above the node.

after removing the color the issue with duplicate the node is solved. how can i use color without braking the node functionality

At a glance, your update method looks very dodgy. See the docs. You should at least check whether the node you get is compatible with the view before you return true.