Gmail keeps empty span containers with br tags after deleting content using backspace

I’m working on a custom email editor that uses special placeholder components. Users can delete these placeholders by hitting the backspace key, but I’m running into a weird issue with Gmail.

When someone deletes the content of the last placeholder element, Gmail doesn’t remove the whole thing. Instead it keeps the empty span wrapper and adds a br tag inside it. This creates visual problems in the email template.

Here’s what my placeholder HTML looks like before deletion:

<span id="wrapper1" data-placeholder="" style="text-size-adjust: 100%;">
    <span id="wrapper2" data-placeholder="" style="text-size-adjust: 100%;">
        <span id="token::a1b2c3d4-5e6f-7890-abcd-ef1234567890" style="color: #ff6b35;" data-placeholder-id="token::a1b2c3d4-5e6f-7890-abcd-ef1234567890" class="placeholder">
            <span class="placeholder-icon">📧</span>
            <span class="placeholder-wrapper">[</span>
            <span class="placeholder-text">
                User Name
            </span>
            <span class="placeholder-wrapper">]</span>
        </span>
    </span>
</span>

After the user deletes everything, Gmail leaves this behind:

<span id="wrapper1" data-placeholder="" style="text-size-adjust: 100%;">
    <span id="wrapper2" data-placeholder="" style="text-size-adjust: 100%;">
        <span id="token::a1b2c3d4-5e6f-7890-abcd-ef1234567890" style="color: #ff6b35;" data-placeholder-id="token::a1b2c3d4-5e6f-7890-abcd-ef1234567890" class="placeholder">
            <br>
        </span>
    </span>
</span>

I tried switching the outer span to a div with inline-block display but that didn’t help. Setting contenteditable to false works but breaks other functionality when multiple placeholders are next to each other. How can I prevent Gmail from keeping these empty containers?

I’ve hit this same Gmail issue in my email template projects. Gmail aggressively preserves content when you edit, which creates this mess. Here’s what worked for me: add a keydown listener for backspace on your placeholder elements. When someone hits backspace, remove the entire wrapper structure before Gmail’s default deletion kicks in. Check if the placeholder content is about to be deleted, then use removeChild on the outermost wrapper span. This way you’re removing the whole structure upfront instead of letting Gmail handle it and leave empty containers behind.

Been dealing with Gmail’s quirky behavior for years and this one’s super annoying. Gmail treats nested spans differently than other elements when you delete stuff. Instead of fighting it, I wrapped my placeholders in a custom element with a CSS pseudo-element as the visual placeholder. When Gmail tries deleting content, it removes the text but the pseudo-element stays put. Then I use an input event listener to catch when the actual content’s gone and remove the entire custom element. This sidesteps Gmail’s span logic completely since it doesn’t recognize custom elements as needing special handling.

gmail really holds on to their markup, huh? a mutation observer is a smart way to go. just watch for deletions and clean up those empty spans right after. i found that to be much more effective than preventing the issue before it happens.