Case ce-0310-firefox-nested-span-drag-en · Scenario scenario-firefox-drag-drop-issues

Nested span generated when dragging text within contenteditable span

OS: Any Any Device: Desktop Any Browser: Firefox 90+ Keyboard: Any Status: draft
firefox drag-drop nested-elements span dom-corruption

Phenomenon

In Firefox, when dragging and dropping text within a <span contenteditable> element, a new nested <span> is generated around the dragged text, leading to unintended nesting and DOM structure corruption.

Reproduction Steps

  1. Open Firefox browser.
  2. Create a <span contenteditable="true"> element with some text.
  3. Select text within the span.
  4. Drag the selected text to another position within the same span.
  5. Drop the text.
  6. Inspect the DOM structure.

Observed Behavior

  1. Nested Span Generation: A new <span> element is generated around the dragged text.
  2. DOM Corruption: The DOM structure becomes nested unnecessarily.
  3. Unintended Nesting: The nesting is not intended and corrupts the document structure.
  4. Firefox-Specific: This issue is specific to Firefox.

Expected Behavior

  • No nested span should be generated.
  • The text should move to the new position without creating new elements.
  • The DOM structure should remain clean and flat.

Impact

  • DOM Corruption: Unnecessary nested elements are created.
  • Styling Issues: Nested spans may cause unexpected styling behavior.
  • Document Structure: The document structure becomes corrupted.
  • Editor Reliability: Rich text editors may fail to handle the corrupted structure.

Browser Comparison

  • Firefox: This issue occurs.
  • Chrome: Not affected.
  • Safari: Not affected.
  • Edge: Not affected.

Notes and Possible Workarounds

Prevent Drag and Drop

const editor = document.querySelector('span[contenteditable]');

// Disable drag and drop entirely
editor.addEventListener('dragstart', (e) => {
  e.preventDefault();
});

Normalize Nested Spans After Drop

function normalizeNestedSpans(element) {
  const spans = element.querySelectorAll('span');
  spans.forEach(span => {
    // Check if span is nested unnecessarily
    if (span.parentElement.tagName === 'SPAN' && 
        span.parentElement.getAttribute('contenteditable') === 'true') {
      // Unwrap the nested span
      const parent = span.parentElement;
      while (span.firstChild) {
        parent.insertBefore(span.firstChild, span);
      }
      parent.removeChild(span);
    }
  });
}

editor.addEventListener('drop', (e) => {
  // ... handle drop ...
  normalizeNestedSpans(editor);
});

Manual Text Movement

editor.addEventListener('mousedown', (e) => {
  const selection = window.getSelection();
  if (selection.rangeCount > 0) {
    const range = selection.getRangeAt(0);
    const selectedText = range.toString();
    
    // Store selected text
    editor.dataset.draggedText = selectedText;
    editor.dataset.dragStart = true;
  }
});

editor.addEventListener('mouseup', (e) => {
  if (editor.dataset.dragStart === 'true') {
    const selection = window.getSelection();
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      const draggedText = editor.dataset.draggedText;
      
      // Delete original text
      const originalRange = /* get original range */;
      originalRange.deleteContents();
      
      // Insert at new position
      range.insertNode(document.createTextNode(draggedText));
      range.collapse(false);
      selection.removeAllRanges();
      selection.addRange(range);
    }
    
    delete editor.dataset.draggedText;
    delete editor.dataset.dragStart;
  }
});

References

Before drag
Select and drag this text
Text selected within span
After drop in Firefox (Bug)
Select and drag this text
Nested span generated around dragged text
vs
Expected
Select and drag this text
No nested span should be generated

Browser compatibility matrix

This matrix shows which browser and OS combinations have documented cases for this scenario. The current case is highlighted. Click on a cell to view other cases.

Current case
Confirmed
Draft
No case documented

All variants (detailed table)

Complete list of all cases for this scenario with full environment details.

Case OS Device Browser Keyboard Status
ce-0310-firefox-nested-span-drag-en Any Any Desktop Any Firefox 90+ Any draft
ce-0554-firefox-drag-drop-textarea-en Any Any Desktop Any Firefox 90+ Any draft
ce-0569 Linux Ubuntu 24.04 Desktop Any Firefox 132.0 US QWERTY confirmed

Playground for this case

Use the reported environment as a reference and record what happens in your environment while interacting with the editable area.

Reported environment
OS: Any Any
Device: Desktop Any
Browser: Firefox 90+
Keyboard: Any
Your environment
Sample HTML:
Event log
Use this log together with the case description when filing or updating an issue.
0 events
Interact with the editable area to see events here.

Comments & Discussion

Have questions, suggestions, or want to share your experience? Join the discussion below.