search

Home  >  Q&A  >  body text

Prevent Chrome from setting font size when pasting HTML into contenteditable

Reappearance:

  1. Run the MVCE snippet on Firefox desktop and Chrome desktop.
  2. Open FF Desktop and copy "foobar" from the source code.
  3. Open Chrome desktop and paste into the target (after the colon in here:)

window.onload = function() {
  const info = document.querySelector('.info'),
    pinfo = document.querySelector('.paste-info'),
    target = document.querySelector('.target');
  setInterval(() => {
    const sel = ".source *, .target *"
    info.innerHTML = '';
    for (const elm of [...document.querySelectorAll(sel)]) {
      info.innerHTML += "TAG: " + elm.tagName + "; TEXT: " + elm.innerText +  "; FONTSIZE: " + window.getComputedStyle(elm)['font-size'] + "<br>";
    }
  }, 1000);
  target.addEventListener('paste', function(e) {
    pinfo.innerHTML += "PASTE HTML: <pre>" + e.clipboardData.getData('text/html').replaceAll('<', '<').replaceAll('>', '>') + '</pre><br>';
  });
};
div[contenteditable] {
  border: 1px solid black;
}
<div class="source" contenteditable=true>Source text: <b>foobar</b></div>

<div style="font-size: 14px">
  <div contenteditable=true class="target">Destination, <h1>paste here:</h1></div>
</div>

<div class="info"></div>
<div class="paste-info"></div>

You will notice:

  1. The clipboard data contains <b>foobar</b> (see what follows PASTE HTML:), but...
  2. The actual pasted HTML has style="font-size: 14px;" set on the b element (the 14px size comes from the contenteditable's parent).

I want no font sizes set on the pasted HTML because they are not specified in the source clipboard data.

Question: How do I force Chrome not to put any font size on the pasted HTML when there is no font size on the source HTML?

I tried a workaround: setting font-size: unset/revert on the source, but this resulted in font-size: unset also appearing in the pasted HTML middle. I don't want any font size to appear in the pasted HTML.


The context of this code is a Chrome extension where I control the text/html data pasted into the target. I can attach a paste event listener on the target contenteditable, but I cannot change the HTML/style of the content after it is pasted.

P粉398117857P粉398117857277 days ago460

reply all(2)I'll reply

  • P粉668113768

    P粉6681137682024-02-27 11:16:48

    Maybe intercept the paste event and change the pasted content to force it to be pasted as plain text using js.

    I added the id of id="editor" on the contenteditable div. And add the following js code:

    const editorEle = document.getElementById('editor');
    
    // Handle the paste event
    editorEle.addEventListener('paste', function (e) {
        // Prevent the default action
        e.preventDefault();
    
        // Get the copied text from the clipboard
        const text = e.clipboardData
            ? (e.originalEvent || e).clipboardData.getData('text/plain')
            : // For IE
            window.clipboardData
            ? window.clipboardData.getData('Text')
            : '';
    
        if (document.queryCommandSupported('insertText')) {
            document.execCommand('insertText', false, text);
        } else {
            // Insert text at the current position of caret
            const range = document.getSelection().getRangeAt(0);
            range.deleteContents();
    
            const textNode = document.createTextNode(text);
            range.insertNode(textNode);
            range.selectNodeContents(textNode);
            range.collapse(false);
    
            const selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
        }
    });

    This is a snippet of it running. Let me know if this solves your problem:

    const editorEle = document.getElementById('editor');
    
    // Handle the `paste` event
    editorEle.addEventListener('paste', function (e) {
        // Prevent the default action
        e.preventDefault();
    
        // Get the copied text from the clipboard
        const text = e.clipboardData
            ? (e.originalEvent || e).clipboardData.getData('text/plain')
            : // For IE
            window.clipboardData
            ? window.clipboardData.getData('Text')
            : '';
    
        if (document.queryCommandSupported('insertText')) {
            document.execCommand('insertText', false, text);
        } else {
            // Insert text at the current position of caret
            const range = document.getSelection().getRangeAt(0);
            range.deleteContents();
    
            const textNode = document.createTextNode(text);
            range.insertNode(textNode);
            range.selectNodeContents(textNode);
            range.collapse(false);
    
            const selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
        }
    });
    
    
    
    
    window.onload = function() {
      const info = document.querySelector('.info'),
        pinfo = document.querySelector('.paste-info'),
        target = document.querySelector('.target');
      setInterval(() => {
        const sel = ".source *, .target *"
        info.innerHTML = '';
        for (const elm of [...document.querySelectorAll(sel)]) {
          info.innerHTML  = "TAG: "   elm.tagName   "; TEXT: "   elm.innerText    "; FONTSIZE: "   window.getComputedStyle(elm)['font-size']   "
    "; } }, 1000); target.addEventListener('paste', function(e) { pinfo.innerHTML = "PASTE HTML:
    "   e.clipboardData.getData('text/html').replaceAll('<', '<').replaceAll('>', '>')   '

    '; }); };
    div[contenteditable] {
      border: 1px solid black;
    }
    Source text: foobar
    Destination,

    paste here:

    reply
    0
  • P粉658954914

    P粉6589549142024-02-27 00:36:47

    You can use to select API.
    The steps are

    • In the paste event handler, get the Range object representing the current selection.
    • Use this Range object to parse the pasted HTML markup into a DocumentFragment object, thanks to the createContextualFragment() method.
    • Delete previously selected content (Range#deleteContents() ).
    • InsertThe DocumentFragment object we created at step 2, where the cursor is.
    • CollapseThe current Range object so that the cursor moves to the end of the newly pasted content.

    Performing all of these steps manually will prevent the browser from "intelligently" processing rich text content; only parsing the content in the clipboard.

    window.onload = function() {
      const info = document.querySelector('.info'),
        pinfo = document.querySelector('.paste-info'),
        target = document.querySelector('.target');
      setInterval(() => {
        const sel = ".source *, .target *"
        info.innerHTML = '';
        for (const elm of [...document.querySelectorAll(sel)]) {
          info.innerHTML = "TAG: " elm.tagName "; TEXT: " elm.innerText "; FONTSIZE: " window.getComputedStyle(elm)['font-size'] "
    "; } }, 1000); target.addEventListener('paste', function(e) { pinfo.innerHTML = "PASTE HTML:
    " e.clipboardData.getData('text/html').replaceAll('<', '<').replaceAll('>', '>') '

    '; e.preventDefault(); const tag = e.clipboardData.getData("text/html") || e.clipboardData.getData("text/plain text"); const sel = getSelection(); const range = sel.getRangeAt(0); const frag = range.createContextualFragment(markup); scope.deleteContents(); range.insertNode(frag); range.collapse(); }); };
    div[contenteditable] {
      border: 1px solid black;
    }
    Source text: foobar
    Destination,

    paste here:

    reply
    0
  • Cancelreply