Bug with leaf nodes on Android


I use ProseMirror with leaf nodes that have non-editable content for mentions ala Twitter, which for the most part works really well.

I have an issue on Android though (both Chrome and Firefox), where delete the node with backspace or inserting right after the node results in a very weird bug:

This is before pressing backspace on Android:


This is what happens when pressing backspace:


Here’s a snippet of the node definition:

export const mentionNodeSpec = {
  attrs: {
    id: {}
  group: "inline",
  inline: true,
  selectable: true,
  toDOM: mentionView,

  parseDOM: [
      tag: "a[data-mention-id]",

      getAttrs: dom => {
        const id = dom.getAttribute("data-mention-id");

        return { id };

And the corresponding view:

const mentionView = node => {
  let note = findNote(node.attrs.id);
  if (!note) {
    return missingNoteView(node);

  let view = document.createElement("a");
  let href = notePath(note);
  view.className = "mention";
  view.setAttribute("data-mention-id", note._id);
  view.innerText = note.title;
  return view;


I’ve tried many variations of this, including using display: inline-block; without any luck so far.

I know many editors based on contenteditable have similar issues on Android, so I’m not sure there’s a good way to fix this, but any help would be very welcome.

Thanks! Nico

Following this discussion: https://github.com/ProseMirror/prosemirror/issues/903#issuecomment-478413748

I’ve tried the wrappers tricks, and it does almost work, but the inline element cannot be deleted anymore.

@marijn Should I post on the GitHub issue instead?

With selectable: true and draggable: false, it more or less works on Chrome on Android, but I still experience the same issue on Firefox.

On Chrome though, adding a line break right before one of the inline element now adds a line break on all other inline elements…

Inline elements with contenteditable=false are a real nightmare on Android :confused:

Yes, browser are disappointingly dumb about uneditable elements in contenteditable. The issue here is that runs IME on the text inside of the node, even though it isn’t editable, and then confuses itself. Have you tried making the nodes display: inline-block? That has helped with this in some cases.

Sounds interesting. If you can reproduce it with a small script a github issue would be useful. Though I can’t guarantee I’ll get to it anytime soon.

Yes, but that didn’t do the trick in my case.

I’ve tried many hacks, and so far I found nothing that worked well both both Chrome and Firefox on Android.

  • Wrapping the node with a display:block element + rendering the child as display: inline-block kinda works, but there are annoying side effects (trailing commas and other punctuation chars can be rendered on the next line, long inline nodes look like block elements, etc.). It doesn’t help at all on Firefox though.

  • I’ve got the best results so far using a 1x1 transparent img, but it’s really hackish. It does work surprisingly well on Chrome on Android, but unfortunately Firefox is still confused.

@marijn I’d be curious to know your opinion on this technique. There might be side-effects, I was afraid of getting this 1x1 img all over the place after some edits, but so far it seems to be working fine.

It’s quite hard to reproduce consistently (of course!), but it does happen from time to time.

I’ve had rather good results with nonsensical <img> nodes as well (it’s what the library currently uses to force a given mark around an empty cursor, for example). It might be worthwhile to try and create some kind of generalized inline-leaf kludge based on those, but I’m currently busy with other stuff so it might be a while until I dig into that.

Interesting. Do you use 0-width images, I’m wondering if there’s an impact when the image is not visible at all.

I’m using an image without an src attribute, which doesn’t show up but still seems to affect text editing.

Do you use display: none or something else?

(I had a typo in the last reply—I meant without src attribute.)

Without an src attribute? Won’t the browser render a broken image icon then?