Using execCommand (Javascript) to copy hidden text to clipboard

JavascriptJqueryHtmlClipboard

Javascript Problem Overview


I'm trying to copy to clipboard without using Flash, I plan to fall back onto Flash with the use of ZeroClipboard if the browser is incompatible with the javascript approach.

I have an onClick listener for the button which looks like:

$(buttonWhereActionWillBeTriggered).click(function(){ 
    var copyDiv = document.getElementById(inputContainingTextToBeCopied);
    copyDiv.focus();
    document.execCommand('SelectAll');
    document.execCommand("Copy", false, null);
}

and an input field as follows:

<input type="text" name="Element To Be Copied" id="inputContainingTextToBeCopied" value="foo"/>

This currently works as expected but the design requires that the field containing the text to be copied is invisible. I have tried both setting type="hidden" and style="display: none" neither of which have succeeded. Both result in the button selecting the whole page and copying the whole content to the user's clipboard.
I'm relatively confident the cause is not browser-based but just in case, I am testing on Chrome (Version 43.0.2357.134 (64-bit)) on Mac OS X 10.10.4.

Is there a way that I can maintain the functionality of when the < input> is visible whilst hiding it? or if not an alternate route I can take?


I'm aware of similar questions, none of which address my problem, either from being too old, not actually using Javascript, or not fitting the particular scenario. Here's a good answer for anyone having similar, less specific issues.

Javascript Solutions


Solution 1 - Javascript

Here's my solution that doesn't use jQuery:

function setClipboard(value) {
    var tempInput = document.createElement("input");
    tempInput.style = "position: absolute; left: -1000px; top: -1000px";
    tempInput.value = value;
    document.body.appendChild(tempInput);
    tempInput.select();
    document.execCommand("copy");
    document.body.removeChild(tempInput);
}

<!DOCTYPE html>
<html>
<head>
<title>Set Clipboard</title>
</head>
<body>
    <button onclick="setClipboard('foo loves bar')">Set Clipboard</button>
</body>
</html>

Solution 2 - Javascript

2019 - was still looking for an answer without offscreen stuff.

What I did is first change the input text field to type="text", copy the text and then change it back to type="hidden". That works well.

<input id="dummy" name="dummy" type="hidden">

<script>
var copyText = document.getElementById("dummy");
copyText.type = 'text';
copyText.select();
document.execCommand("copy");
copyText.type = 'hidden';
</script>

Solution 3 - Javascript

--Update--

>Document.execCommand() > >[1] Before Firefox 41, clipboard capability needed to be enabled in the user.js preference file. See A brief guide to Mozilla preferences for more information. If the command wasn't supported or enabled, execCommand was raising an exception instead of returning false. In Firefox 41 and later, clipboard capability is enabled by default in any event handler that is able to pop-up a window (semi-trusted scripts).

Since Firefox version 41 Document.execCommand() now works. So no need to use a fallback anymore.


Since browsers seem to behave differently when it comes to clipboard access, it took me a while to get my head around it.

It's pretty similar to your solution, but the difference is to create a temporary element and fill it with the input value. That way we can keep the input's display property set to none.

There is also a workaround for IE which uses window.clipboardData.

Firefox would not let me access the clipboard at all. So I had to add a prompt to let users manually copy the input value. Sure a prompt is ugly, but you could just use a modal like a window, which would do the same.

Since this seems to be a knotty thing, I am on Win7 (64 bit) and tested in

Chrome - Version 43.0.2357.134 m

IE - Version 11.0.9600.17914

and Firefox is irrelevant because it would not let me access it anyway.

var copyBtn   = $("#copy-btn"),
    input     = $("#copy-me");

function copyToClipboardFF(text) {
  window.prompt ("Copy to clipboard: Ctrl C, Enter", text);
}

function copyToClipboard() {
  var success   = true,
      range     = document.createRange(),
      selection;

  // For IE.
  if (window.clipboardData) {
    window.clipboardData.setData("Text", input.val());        
  } else {
    // Create a temporary element off screen.
    var tmpElem = $('<div>');
    tmpElem.css({
      position: "absolute",
      left:     "-1000px",
      top:      "-1000px",
    });
    // Add the input value to the temp element.
    tmpElem.text(input.val());
    $("body").append(tmpElem);
    // Select temp element.
    range.selectNodeContents(tmpElem.get(0));
    selection = window.getSelection ();
    selection.removeAllRanges ();
    selection.addRange (range);
    // Lets copy.
    try { 
      success = document.execCommand ("copy", false, null);
    }
    catch (e) {
      copyToClipboardFF(input.val());
    }
    if (success) {
      alert ("The text is on the clipboard, try to paste it!");
      // remove temp element.
      tmpElem.remove();
    }
  }
}

copyBtn.on('click', copyToClipboard);

#copy-me {
    display:none
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="Element To Be Copied" id="copy-me" value="foo loves bar"/>
<button id="copy-btn">Copy</button><br/><br/>
<textarea placeholder="paste here"></textarea>

Solution 4 - Javascript

Thanks to the help of @DavidDomain, I found a somewhat hacky, but functional approach.

Firstly, I moved the input way off screen and modified some properties, resulting in this:

<input type="text" name="Element To Be Copied" id="inputContainingTextToBeCopied" value="foo" style="display:none; position: relative; left: -10000px;"/>

display:none was added after the following modifications to the js

After that, the comment from @Pokkanome let me into modifying the onClick function like so:

$(buttonWhereActionWillBeTriggered).click(function(){ 
    var copyDiv = document.getElementById(inputContainingTextToBeCopied);
    copyDiv.style.display = 'block';
    copyDiv.focus();
    document.execCommand('SelectAll');
    document.execCommand("Copy", false, null);
    copyDiv.style.display = 'none';
}

I'm unsure if it's possible to copy from a hidden div using this method, which would make sense in terms of browser security as giving unquestioned access to the clipboard is going to be somewhat risky. The approach taken had the same intended result though.

Solution 5 - Javascript

I have a less outdated Solution here:

Using this script, you can copy your data. It's much smaller than the past scripts provided.

What the script does is use an Input that is hidden off the side of the Screen either with CSS or Inline-Styles, and then selects it quickly and runs the copy command.

function copyFunc() {
  var copyText = document.getElementById("copyInp");
  copyText.select();
  document.execCommand("copy"); //this function copies the text of the input with ID "copyInp"
}

<input type="text" value="StuffYaWantCopied" id="copyInp" style="position:absolute;left:-1000px;top:-1000px;">
  <a onclick="copyFunc()" style="cursor:cell;">
     Click here to Copy!
  </a>

For Bonus, I made a small Clipboard API that can select Elements Dynamically and retrieve Text from them using Contenteditable Divs and Dynamic Variables: https://codepen.io/SkylerSpark/pen/OJJqxWX

Also, go see Ciprians Answer below about using the new Permissions API to send text directly to the clipboard with permissions allowed by the user, it's not fully supported, but it's available in the latest browsers (I know it actually works in chrome right now, but I haven't tested any other browsers): https://stackoverflow.com/a/58099014/11165703

Solution 6 - Javascript

You can simply use opacity:0.00000000000001 to hide the input tag, then use javascript to copy the hidden text to clipboard

function myFunction() {
  var copyText = document.getElementById("myInput");
  copyText.select();
  copyText.setSelectionRange(0, 99999)
  document.execCommand("copy");
  alert("Text copied successfully");
}

<input type="text" value="===your text here===" id="myInput" style="opacity:0.00000000000001">
<button onclick="myFunction()">Copy</button>

Solution 7 - Javascript

An alternative workaround that works in all browser is, instead of hiding the element, you can set its opacity as 0 with absolute position.

#copy-me {
    position: absolute;
    opacity: 0;
}

Solution 8 - Javascript

You can use window.navigator for this:

navigator.clipboard.writeText('this will be copied to the clipboard');

Solution 9 - Javascript

What works to me was:

<div>
  <a class="copyBtn">Copy</a>
  <input class="d-none" value="teste">
</div>

and:

$('.copyBtn').on('click', function(e) {
  e.preventDefault();
  var input = $(this).parent().find(".dirVal");
  $(input).removeClass("d-none");
  input.select();

  document.execCommand('copy');
  $(input).addClass("d-none");
  callNotify("Parabéns!", "Caminho copiado para área de transferência!", "success");
});

Solution 10 - Javascript

What about using this: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText

navigator.clipboard.writeText("<empty clipboard>").then(function() {
  /* clipboard successfully set */
}, function() {
  /* clipboard write failed */
});

Solution 11 - Javascript

just do it!

.blind {
    overflow: hidden;
    position: absolute;
    clip: rect(0 0 0 0);
    width: 1px;
    height: 1px;
    margin: -1px;
}
<textarea id="copy" class="blind">
your copy text here!
</textarea>
copyClipboard(document.getElementById('copy'));

function copyClipboard(el) {
  el.select();
  window.document.execCommand('copy');
}

https://gist.github.com/seunggabi/7ae53c100d647cb19c48047cff9b7019

Solution 12 - Javascript

Two approaches that worked for me:

Approach 1: In this approach, the input element is initially hidden, and the copy function unhides it, selects and copies the text then hides it again.

<script>
  function copyLinkToClipboardViaHiddenField() {
    el = document.querySelector("#input");
    el.style.display = "block";
    var copyText = document.querySelector("#input");
    copyText.select();
    document.execCommand("copy");
    el.style.display = "none";
    document.getElementById("copylink").innerText = "copied OK!";
    document.getElementById("copylink").href = "";
    document.getElementById("copylink").style.color = "black";
    document.getElementById("copylink").style.textDecoration = "none";
    return false; // prevents click doing anything
  }

</script>
<input id="input"
       type="text"
       style="display: none;"
       value="https://www.example.org/ViaHiddenField"/>
<a href="javascript:void(0)"
   onclick="return copyLinkToClipboardViaHiddenField()"
   id="copylink"
   style="text-decoration: underline;color: blue;">copy link ViaHiddenField</a>

Approach 2: In this approach, a new input element is created and appended to the bottom of the document body, its value is copied, then the element is removed.

<script>
  function copyLinkToClipboardViaAppendElement() {
    el = document.createElement("input");
    el.setAttribute('type', 'text');
    el.setAttribute('value', "https://www.example.org/ViaAppendElement");
    document.body.appendChild(el)
    el.select();
    console.log(el)
    document.execCommand("copy");
    el.parentNode.removeChild(el);
    document.getElementById("copylink").innerText = "copied OK!";
    document.getElementById("copylink").href = "";
    document.getElementById("copylink").style.color = "black";
    document.getElementById("copylink").style.textDecoration = "none";
    return false; // prevents click doing anything;
  }

</script>
<a href="javascript:void(0)"
   onclick="return copyLinkToClipboardViaAppendElement()"
   id="copylink"
   style="text-decoration: underline;color: blue;">copy link ViaAppendElement</a>

Solution 13 - Javascript

To copy the text to clibboard it has to be visible. So I created an input type=text but set style display:none and used jquery to perform show() and hide() around copying.

<input type=text id='me' value='bla' style='display:none;'>
<button onclick='
$("#me").show(); 
var copyText = document.getElementById("me"); 
copyText.select();
copyText.setSelectionRange(0, 99999);   
document.execCommand("copy"); 
$("#me").hide(); 
alert("Link copied to clipboard");
'></button> 

Solution 14 - Javascript

Here's an easy, though hacky answer to this that seems to work for me. Rather than using display: none; use this:

height: 0px;
width: 0px;
overflow: hidden;
position: absolute;

This allows for selection while still hiding the textarea and not affecting the design.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAaron CritchleyView Question on Stackoverflow
Solution 1 - JavascriptDan StevensView Answer on Stackoverflow
Solution 2 - JavascriptRickView Answer on Stackoverflow
Solution 3 - JavascriptDavidDomainView Answer on Stackoverflow
Solution 4 - JavascriptAaron CritchleyView Answer on Stackoverflow
Solution 5 - JavascriptMister SirCodeView Answer on Stackoverflow
Solution 6 - JavascriptMohamed HaseemView Answer on Stackoverflow
Solution 7 - JavascriptDinesh MView Answer on Stackoverflow
Solution 8 - JavascriptTimView Answer on Stackoverflow
Solution 9 - JavascriptDouglas LopesView Answer on Stackoverflow
Solution 10 - JavascriptCiprianView Answer on Stackoverflow
Solution 11 - JavascriptseunggabiView Answer on Stackoverflow
Solution 12 - JavascriptDuke DougalView Answer on Stackoverflow
Solution 13 - JavascriptDesireeView Answer on Stackoverflow
Solution 14 - JavascriptLukeView Answer on Stackoverflow