Anyway to disallow keyboard event handling when an atom node is in focus

I want to implement a tag input, and an example of what I want to do is this

      tag: {
        content: "inline*",
        marks: "",
        toDOM(node) {
          return ["tag", 0]
        parseDOM: [{ tag: "tag" }]
      tags: {
        content: "tag*",
        marks: "",
        toDOM(node) {
          return ["tags", 0]
        parseDOM: [{ tag: "tags" }]

I use a custom view for tags, it is implemented the same way as the above codepen link, i.e. I use an input box to gather user input.

Everything worked well till I changed tags.atom = true. After tags become atom, even when the input is under focus, prosemirror editor will handle the keyboard event and insert what I type in the input box into the same line of the document. I tried stopPropagation() in both the keyup and keydown events, but doesn’t work.

The reason I want it to be atom is that I want it to work with the gapCursor().

I wonder how I can solve this?

You can probably solve this with NodeView.stopEvent.

Thank you. This solution works well.

I have a follow-up question. How can I naturally move the cursor away (up or down) from this customized NodeView.

Currently, whenever the cursor is moved into this node, I let the input box in focus, so the user can start typing.

I achieved this by

  selectNode() {
    console.log('node selected')

  deselectNode() {

But I don’t know how to move the cursor away from this node. right now, a user has to manually click other paragraphs to dismiss the selection of this node:

I tried:

if (e.code === 'ArrowUp') {
        const pos = getPos() - 1;
        view.dispatch(, pos)));

I can’t seem to get the position correct. This moves the cursor to a strange place (not the previous paragraph.) Although the current node is losing focus, I still can’t type anything.

using the ResolvedPos also doesn’t seem to work too:


if I check its nodeBefore and nodeAfter, I will get null. If I check its parent, I will get the same node back i.e. the “tags” node.

I expect it to return the paragraph node before the tags node, so that I can query the paragraph node’s last possible cursor position and change the selection to that location.

I found a solution to my problem from the codemirror example:

maybeEscape(unit, dir) {
    let {state} =, {main} = state.selection
    if (!main.empty) return false
    if (unit == "line") main = state.doc.lineAt(main.head)
    if (dir < 0 ? main.from > 0 : < state.doc.length) return false
    let targetPos = this.getPos() + (dir < 0 ? 0 : this.node.nodeSize)
    let selection = Selection.near(this.view.state.doc.resolve(targetPos), dir)
    let tr =