Scenario

Link pasting behavior differs across browsers

When pasting links into contenteditable elements, different browsers handle the link data differently. Some browsers paste only the URL, while others preserve the link title and HTML structure.

paste
Scenario ID
scenario-paste-link-behavior

Details

When pasting links into contenteditable elements, different browsers handle the link data differently. Some browsers paste only the URL, while others preserve the link title and HTML structure.

Observed Behavior

  1. URL only: Some browsers paste only the URL as plain text
  2. Link structure lost: Link title and HTML structure are not preserved
  3. Inconsistent behavior: Different browsers handle link pasting differently
  4. Context loss: Important link context (title) is lost

Browser Comparison

  • Safari: Only URL is pasted (this issue)
  • Chrome: Link with title and URL is pasted correctly
  • Firefox: Link with title and URL is pasted correctly
  • Edge: Link with title and URL is pasted correctly

Impact

  • Loss of context: Link titles provide important context that is lost
  • Manual work: Users must manually recreate links with titles
  • Inconsistent behavior: Different from other browsers, causing confusion
  • User frustration: Users expect links to be pasted with titles

Workarounds

Clipboard API

Use Clipboard API to read link data and manually create link elements:

editor.addEventListener('paste', async (e) => {
  e.preventDefault();
  
  const clipboardData = e.clipboardData || window.clipboardData;
  const pastedText = clipboardData.getData('text/plain');
  
  // Check if pasted text is a URL
  const urlPattern = /^https?:\/\/.+/;
  if (urlPattern.test(pastedText.trim())) {
    // Try to get link title from clipboard
    let linkTitle = pastedText;
    
    try {
      const htmlData = clipboardData.getData('text/html');
      if (htmlData) {
        const parser = new DOMParser();
        const doc = parser.parseFromString(htmlData, 'text/html');
        const link = doc.querySelector('a');
        if (link) {
          linkTitle = link.textContent || link.href;
        }
      }
    } catch (err) {
      // Fallback to URL
    }
    
    // Create link element
    const link = document.createElement('a');
    link.href = pastedText.trim();
    link.textContent = linkTitle;
    link.target = '_blank';
    link.rel = 'noopener noreferrer';
    
    // Insert link at cursor position
    const selection = window.getSelection();
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      range.deleteContents();
      range.insertNode(link);
      range.collapse(false);
      selection.removeAllRanges();
      selection.addRange(range);
    }
  }
});

Fallback detection

Detect plain URL pastes and convert them to links:

function isUrl(text) {
  const urlPattern = /^https?:\/\/.+/;
  return urlPattern.test(text.trim());
}

function convertUrlToLink(url) {
  const link = document.createElement('a');
  link.href = url;
  link.textContent = url;
  return link;
}

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-0301-safari-paste-link-url-only-en macOS 13-14 Desktop or Laptop Any Safari 16+ US QWERTY draft

Cases

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

Related Scenarios

Other scenarios that share similar tags or category.

Tags: paste, clipboard

Clipboard API paste does not work in contenteditable

When using the Clipboard API (navigator.clipboard.readText() or navigator.clipboard.read()) to programmatically paste content into a contenteditable region, the paste operation may fail or not work as expected.

2 cases

Comments & Discussion

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