Scenario

Nested formatting elements create complex DOM structures

Applying multiple formatting operations (bold, italic, underline, etc.) creates nested HTML elements that can become complex and hard to manage. Browsers handle nested formatting differently, and the resulting DOM structure can be inconsistent.

formatting
Scenario ID
scenario-nested-formatting

Details

Applying multiple formatting operations (bold, italic, underline, etc.) creates nested HTML elements that can become complex and hard to manage. Browsers handle nested formatting differently, and the resulting DOM structure can be inconsistent.

Observed Behavior

Scenario 1: Applying bold then italic

  • Chrome/Edge: May create <b><i>text</i></b> or <i><b>text</b></i>
  • Firefox: Similar nested structure, order may differ
  • Safari: Nesting order most inconsistent

Scenario 2: Removing nested formatting

  • Chrome/Edge: May leave empty elements or partial nesting
  • Firefox: Similar issues
  • Safari: Formatting removal most likely to break structure

Scenario 3: Overlapping formatting

  • Chrome/Edge: May create complex nested structures
  • Firefox: Similar behavior
  • Safari: Most complex nesting

Scenario 4: Formatting normalization

  • Chrome/Edge: No automatic normalization
  • Firefox: Similar lack of normalization
  • Safari: Normalization behavior varies

Impact

  • Complex and bloated DOM
  • Difficulty managing formatting state
  • Inconsistent formatting structure
  • Need for normalization logic

Browser Comparison

  • Chrome/Edge: Generally creates more predictable nesting
  • Firefox: Similar nesting behavior
  • Safari: Most inconsistent nesting

Workaround

Normalize formatting structure:

function normalizeFormatting(element) {
  // Normalize nested formatting to consistent structure
  const formattingTags = ['b', 'strong', 'i', 'em', 'u', 's', 'strike'];
  
  formattingTags.forEach(tag => {
    const elements = element.querySelectorAll(tag);
    elements.forEach(el => {
      // If element only contains whitespace, remove it
      if (!el.textContent.trim()) {
        const parent = el.parentNode;
        while (el.firstChild) {
          parent.insertBefore(el.firstChild, el);
        }
        el.remove();
        return;
      }
      
      // If parent has same tag, merge
      if (el.parentElement && el.parentElement.tagName.toLowerCase() === tag) {
        const parent = el.parentElement;
        while (el.firstChild) {
          parent.insertBefore(el.firstChild, el);
        }
        el.remove();
      }
    });
  });
  
  // Ensure consistent tag usage (b vs strong, i vs em)
  element.querySelectorAll('strong').forEach(strong => {
    const b = document.createElement('b');
    while (strong.firstChild) {
      b.appendChild(strong.firstChild);
    }
    strong.parentNode.replaceChild(b, strong);
  });
  
  element.querySelectorAll('em').forEach(em => {
    const i = document.createElement('i');
    while (em.firstChild) {
      i.appendChild(em.firstChild);
    }
    em.parentNode.replaceChild(i, em);
  });
}

element.addEventListener('input', () => {
  requestAnimationFrame(() => {
    normalizeFormatting(element);
  });
});

References

Scenario flow

Visual view of how this scenario connects to its concrete cases and environments. Nodes can be dragged and clicked.

React Flow mini map

Variants

Each row is a concrete case for this scenario, with a dedicated document and playground.

Case OS Device Browser Keyboard Status
ce-0112-nested-formatting-complex Windows 11 Desktop or Laptop Any Chrome 120.0 US draft
ce-0128-nested-formatting-removal Windows 11 Desktop or Laptop Any Chrome 120.0 US draft
ce-0160-nested-formatting-order-inconsistent Windows 11 Desktop or Laptop Any Safari 17.0 US draft

Browser compatibility

This matrix shows which browser and OS combinations have documented cases for this scenario. Click on a cell to view the specific case.

Confirmed
Draft
No case documented

Cases

Open a case to see the detailed description and its dedicated playground.

Related Scenarios

Other scenarios that share similar tags or category.

Tags: formatting, bold, italic

List formatting is lost when editing list items

When editing text within list items, formatting such as bold, italic, or links may be lost or behave unexpectedly. The list structure itself may also be lost when certain operations are performed, such as pasting content or applying formatting.

3 cases
Tags: formatting, bold, italic

Typing adjacent to formatted elements causes unexpected behavior

When typing text next to formatted elements (links, bold, italic, etc.) in contenteditable, the input events may include the formatted element's text in event.data, selection ranges may include the formatted element, and text may be inserted into the formatted element instead of after it. This occurs across different browsers and input methods.

1 case
Tags: structure

Blockquote editing behavior varies across browsers

Editing text within blockquote elements in contenteditable behaves inconsistently across browsers. Pressing Enter, applying formatting, or pasting content may break the blockquote structure, create nested blockquotes, or behave unexpectedly.

4 cases
Tags: formatting

Code block editing behavior varies across browsers

Editing text within code blocks (<pre><code>) in contenteditable elements behaves inconsistently across browsers. Line breaks, indentation, whitespace preservation, and formatting may be handled differently, making it difficult to maintain code formatting.

4 cases

Comments & Discussion

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