Skip to content

Instantly share code, notes, and snippets.

@scottoffen
Last active April 13, 2022 08:38
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save scottoffen/1363764209058daafed2 to your computer and use it in GitHub Desktop.
Save scottoffen/1363764209058daafed2 to your computer and use it in GitHub Desktop.
JavaScript Copy To Clipboard Example
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Copy To Clipboard Example</title>
</head>
<body>
<input id="txtToCopy" type="text">
<button id="btnCopy">Copy!</button>
<script>
var txt = document.getElementById('txtToCopy');
var btn = document.getElementById('btnCopy');
var clipboard =
{
data : '',
intercept : false,
hook : function (evt)
{
if (clipboard.intercept)
{
evt.preventDefault();
evt.clipboardData.setData('text/plain', clipboard.data);
clipboard.intercept = false;
clipboard.data = '';
}
}
};
window.addEventListener('copy', clipboard.hook);
btn.addEventListener('click', onButtonClick);
function onButtonClick ()
{
clipboard.data = txt.value;
if (window.clipboardData)
{
window.clipboardData.setData('Text', clipboard.data);
}
else
{
clipboard.intercept = true;
document.execCommand('copy');
}
}
</script>
</body>
</html>

JavaScript Button Copy-To-Clipboard

While this example is not a definitive solution, it focuses on being future-proof rather than backwards compatible. Successful testing occurred in the following browsers on Windows 7 64-bit:

  • Microsoft Internet Explorer 11 (11.0.9600.17843)
  • Google Chrome 46 (46.0.2490.80 m)
  • Mozilla Firefox 41 (41.0.2)
  • Opera 32 (32.0.1948.44)

If you test it and find it to be working in other browsers, please make note of the browser, version and platform (OS) in the comments.

At the time of this writing the ClipboardEvent API is still an experimental technology, and is subject to change. This reference will be updated as such changes that are material to this example come to my attention.

The Encapsulated Object

This consists of a simple object with two properties and a single method.

var clipboard =
{
	data      : '',
	intercept : false,
	hook      : function (evt)
	{
		if (clipboard.intercept)
		{
			evt.clipboardData.setData('text/plain', clipboard.data);
			evt.preventDefault();

			clipboard.intercept = false;
			clipboard.data      = '';
		}
	}
};
Name Default Description
data empty string This property holds the data that we want placed into the clipboard.
intercept false Indicates whether or not the hook should intercept the triggered event.
hook function Function that will be called whenever the copy event is triggered.

Intercepting The Clipboard Event

In this example, we intercept the copy event on the window object. This event is triggered both from the Copy browser context menu item or when the user presses the Ctrl+c (or other platform appropriate keyboard shortcut). Because of this, we do not need to capture keystrokes as a separate event handler to trigger the same code.

window.addEventListener('copy', clipboard.hook);

Unless and until this event listener is removed, every attempt to copy anything on the page will hit our event handler.

The Clipboard Hook

Our clipboard.hook event handler is called when the copy event is triggered. It first looks to see if it should intercept the method, using it's own intercept property. If so, it takes the value currently in clipboard.data and puts it on the clipboard. The call to preventDefault then stops the default action - copying whatever was selected into the clipboard - from happening, and overriding our data.

function (evt)
{
    if (clipboard.intercept)
    {
        evt.clipboardData.setData('text/plain', clipboard.data);
        evt.preventDefault();

        clipboard.intercept = false;
        clipboard.data      = '';
    }
}

Here we also clear our clipboard.data and set clipboard.intercept to false. Failing to do this last update will result in every attempt to copy data using standard means (context menu and keyboard shortcuts) on the page being intercepted by our method, instead of the user copying what they thought they were copying. Unless this is your intention, it's best not to frustrate users, even if you can't think of a reason they might want to copy anything else on the page.

While it might be possible to do otherwise, the example here only sets textual data, and that is our primary use case.

Triggering A Copy Event

We want to use a DOM event - in this case, a button click - trigger our copy function. Not surprisingly, the first thing we want to do when the button is click is set the value of clipboard.data to the desired data.

Next, we're going to check DOM support for window.clipboardData. While it's true that Microsoft has (mostly) deprecated this object, if it does exist, then that means that the code is running in an old version of Internet Explorer. If that's the case, we don't need to trigger a copy event; we can just populate the clipboard using window.clipboardData.setData method.

Otherwise, we need to trigger the copy event. But before doing that, we should set clipboard.intercept to true. Otherwise, our hook won't execute, and the default action will occur.

function onButtonClick ()
{
	clipboard.data = txt.value;

	if (window.clipboardData)
	{
		window.clipboardData.setData('Text', clipboard.data);
	}
	else
	{
		clipboard.intercept = true;
		document.execCommand('copy');
	}
}

Limitations of the Clipboard API

Take a minute to check out the entry for the Clipboard API at CanIUse.com. There are a few things important to note.

  1. There are known issues with Safari (Mac and iOS) and older versions of both Firefox (pre 41) and Chrome (pre 31) where the copy event could not be triggered via document.execCommand.

  2. No browser tested thus far is able to successfully create a ClipboardEvent object using the documented constructor.

  3. According to the documentation, the document.execCommand method should only be available when the document is in design mode, but at the time of this writing (Oct 2015), that is not the case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment