Scenario

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.

formatting
Scenario ID
scenario-code-block-editing

Details

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.

Observed Behavior

Scenario 1: Line breaks in code blocks

  • Chrome/Edge: Line breaks may be preserved or converted to <br> tags
  • Firefox: Similar behavior but may handle differently
  • Safari: May not preserve line breaks correctly

Scenario 2: Indentation and spaces

  • Chrome/Edge: Multiple spaces may be collapsed despite <pre> tag
  • Firefox: Similar whitespace handling issues
  • Safari: Whitespace preservation inconsistent

Scenario 3: Typing in code blocks

  • Chrome/Edge: Text may be inserted but formatting may be lost
  • Firefox: Similar issues
  • Safari: Behavior varies

Scenario 4: Pasting code into code blocks

  • Chrome/Edge: May preserve or lose formatting
  • Firefox: More likely to lose formatting
  • Safari: Most inconsistent behavior

Impact

  • Difficulty maintaining code formatting
  • Loss of indentation and whitespace
  • Inconsistent code block editing experience
  • Need for workarounds to preserve code structure

Browser Comparison

  • Chrome/Edge: Generally better code block handling
  • Firefox: More likely to lose formatting
  • Safari: Most inconsistent behavior

Workaround

Implement custom code block handling:

element.addEventListener('input', (e) => {
  const codeBlocks = element.querySelectorAll('pre code, code');
  codeBlocks.forEach(code => {
    // Preserve whitespace
    if (!code.style.whiteSpace) {
      code.style.whiteSpace = 'pre';
    }
    
    // Prevent formatting inside code
    code.addEventListener('beforeinput', (e) => {
      if (e.inputType.startsWith('format')) {
        e.preventDefault();
      }
    });
  });
});

// Handle paste in code blocks
element.addEventListener('paste', (e) => {
  const selection = window.getSelection();
  if (selection.rangeCount === 0) return;
  
  const range = selection.getRangeAt(0);
  const code = range.startContainer.closest('code, pre');
  
  if (code) {
    e.preventDefault();
    const text = e.clipboardData.getData('text/plain');
    
    // Preserve whitespace and line breaks
    const lines = text.split('\n');
    const fragment = document.createDocumentFragment();
    
    lines.forEach((line, index) => {
      fragment.appendChild(document.createTextNode(line));
      if (index < lines.length - 1) {
        fragment.appendChild(document.createElement('br'));
      }
    });
    
    range.deleteContents();
    range.insertNode(fragment);
  }
});

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-0108-code-block-whitespace-chrome Windows 11 Desktop or Laptop Any Chrome 120.0 US draft
ce-0136-code-block-paste-formats Windows 11 Desktop or Laptop Any Firefox 120.0 US draft
ce-0147-code-block-line-breaks-lost Windows 11 Desktop or Laptop Any Chrome 120.0 US draft
ce-0157-code-block-formatting-allowed Windows 11 Desktop or Laptop Any Chrome 120.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

execCommand is deprecated but still widely used for formatting

The document.execCommand() API, which is commonly used to apply formatting (bold, italic, etc.) in contenteditable regions, has been deprecated. However, there is no complete replacement, and many implementations still rely on it. This creates uncertainty about future browser support.

1 case
Tags: formatting

Font family changes behave inconsistently

Changing font family in contenteditable elements behaves inconsistently across browsers. The font-family CSS property may be applied inline, as a style attribute, or may not be applied at all. The behavior also varies when editing text after applying a font.

3 cases
Tags: formatting

insertHTML breaks DOM structure and formatting

When using document.execCommand('insertHTML', ...) to insert HTML content into a contenteditable region, the DOM structure may be broken or reformatted unexpectedly. Nested elements may be flattened or reorganized.

1 case
Tags: formatting

Link insertion and editing behavior varies across browsers

When inserting or editing links in contenteditable elements, the behavior varies significantly across browsers. Creating links, editing link text, and removing links can result in unexpected DOM structures or lost formatting.

3 cases

Comments & Discussion

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