tutorial // May 06, 2022
How to Add a Copy to Clipboard Button Using JavaScript
How to create a function which receives a string of text to copy to the users clipboard when called.
Getting started
For this tutorial, we're going to use CheatCode's full-stack JavaScript framework, Joystick. Joystick brings together a front-end UI framework with a Node.js back-end for building apps.
To begin, we'll want to install Joystick via NPM. Make sure you're using Node.js 16+ before installing to ensure compatibility (give this tutorial a read first if you need to learn how to install Node.js or run multiple versions on your computer):
Terminal
npm i -g @joystick.js/cli
This will install Joystick globally on your computer. Once installed, next, let's create a fresh project:
Terminal
joystick create app
After a few seconds, you will see a message logged out to cd
into your new project and run joystick start
:
Terminal
cd app && joystick start
After this, your app should be running and we're ready to get started.
Adding a Joystick component
In the app we just created, an example page component that's already wired up to our router was created for us at /ui/pages/index/index.js
. To get started, we're going to open this file up and replace its contents with a skeleton component that we'll build our copy to clipboard functionality on:
/ui/pages/index/index.js
import ui from '@joystick.js/ui';
const Index = ui.component({
render: () => {
return `
<div>
</div>
`;
},
});
export default Index;
Here, we begin by importing the ui
object from the @joystick.js/ui
package: the UI framework portion of CheatCode's Joystick framework. Next, we create a variable const Index
and assign it to a call to ui.component()
. This method creates a new Joystick component for us using the options we pass to it as an object.
New to Joystick or never heard of it? Get a crash course on building your UI with @joystick.js/ui in this tutorial.
On that object, we've added a single property render
which is assigned to a function returning the HTML we want to render on screen when we load this component in our app. For now, we're just returning a string with an empty <div></div>
tag.
/ui/pages/index/index.js
import ui from '@joystick.js/ui';
const Index = ui.component({
css: `
div {
display: flex;
}
div button {
margin-left: 10px;
}
`,
render: () => {
return `
<div>
<input type="text" />
<button class="copy">Copy</button>
</div>
`;
},
});
export default Index;
Building out the HTML, next, we want to add an <input />
tag with a type
of text
and a button with a class
of copy
. Our goal will be to take whatever we type into the input and when we click the "Copy" button, copy it to the clipboard. Just above this, we've added some simple CSS to clean up the display of our input and button so they sit next to each other on screen.
Adding a copy to clipboard
Next, we need to wire up the button that will handle the copy of our text to the clipboard.
/ui/pages/index/index.js
import ui from '@joystick.js/ui';
const Index = ui.component({
events: {
'click .copy': (event, component) => {
const input = component.DOMNode.querySelector('input');
component.methods.copyToClipboard(input.value);
},
},
css: `...`,
render: () => {
return `
<div>
<input type="text" />
<button class="copy">Copy</button>
</div>
`;
},
});
export default Index;
In order to handle the copy event, we need to add an event listener on our button so that when it's clicked, we can get the current input value and then hand it off to our copy function.
Here, we're adding an option to our component events
which is assigned to an object where each property name is the combination of a type of DOM event we want to listen for and the element we want to listen for it on <event> <element>
. To that property, we assign a function that we want Joystick to call whenever that event is detected on that element.
For our needs, we want to get the current value of the <input />
tag we're rendering down in our HTML. To do it, we anticipate that Joystick will pass us the raw DOM event that's taking place as the first argument to our function, and as the second argument, the current component instance.
On that instance, Joystick gives us access to the current component as it's rendered in the browser at component.DOMNode
. This is a plain, JavaScript DOM node object, which means that we can perform any standard JavaScript methods on it. Here, we're calling to querySelector()
to say "within this element—component.DOMNode
—look for an element called input
."
With that element, next, we call to component.methods.copyToClipboard()
passing in the value
property of our input
(this will contain the text value currently in the input).
Our last step is to wire up that methods.copyToClipboard()
function to make this work.
/ui/pages/index/index.js
import ui from '@joystick.js/ui';
const Index = ui.component({
methods: {
copyToClipboard: (text = '') => {
const textarea = document.createElement("textarea");
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
},
},
events: {
'click .copy': (event, component) => {
const input = component.DOMNode.querySelector('input');
component.methods.copyToClipboard(input.value);
},
},
css: `...`,
render: () => {
return `
<div>
<input type="text" />
<button class="copy">Copy</button>
</div>
`;
},
});
export default Index;
This is the important part. On a Joystick component, we can define arbitrary functions we want available under the methods
object. Here, we've added copyToClipboard()
as one of those methods ("method" is just the proper name for a function defined on an object in JavaScript), taking in a string of text
(here, the value we just pulled from our input, but potentially any string we want to copy to the clipboard).
Because JavaScript lacks a native "copy to clipboard" feature, in order to make this work, we need to do a slight hack.
Inside of this function, first we want to dynamically create a <textarea></textarea>
element in memory. Next, we assign the value of that textarea
element to the text
we passed into copyToClipboard()
. Once this is set, we dynamically append the textarea
to the <body></body>
tag of our browser and then immediately call the .select()
method on it.
Note: the
document.execCommand()
function is listed as being deprecated, however, has well-established support across browsers. The deprecation status is due to an inconsistent implementation across major browsers which is deemed as the rational for flagging it as deprecated. It still works for our needs—and browsers have kept it implemented due to its wide usage—so while you shouldn't worry immediately, make sure it works at the time you read this. You can learn more about the deprecation status in this StackOverflow post.
Next, we use the document.execCommand()
function passing the string "copy"
to tell the browser to perform the copy command which will copy whatever is currently selected in the browser to the clipboard. Finally, we call to document.body.removeChild(textarea)
to remove the <textarea></textarea>
we just injected.
That's it! Now, if we open up our app in the browser at http://localhost:2600
, when we click our button the current value of our input will be passed to methods.copyToClipboard()
and automatically be copied to the clipboard.
Wrapping Up
In this tutorial, we learned how to create a simple function for copying text to the clipboard. We learned about wiring up a simple UI component using Joystick and then, when clicking a button, copying the current text of an input to the clipboard.