JavaScript Clipboard API
Table of Contents + −
In the previous lesson, we learned how to keep data for a single browser tab with session storage. Now let’s use the Clipboard API to copy text to and read text from the system clipboard.
📋 What is the Clipboard API?
The Clipboard API lets your page write text to the clipboard and read text back from it. It lives on the navigator.clipboard object that every modern browser provides.
The two methods you reach for most are listed below.
| Method | Meaning | Returns |
navigator.clipboard.writeText(text) | Copies a string to the clipboard | A promise |
navigator.clipboard.readText() | Reads the current clipboard text | A promise that resolves to the text |
Both methods return a promise, so you wait for them with await.
✍️ Copying Text with writeText()
navigator.clipboard.writeText() takes the string you want to copy and returns a promise. The promise resolves once the text is on the clipboard.
async function copyText(text) { await navigator.clipboard.writeText(text); console.log("Text copied:", text);}
copyText("Hello, clipboard!");Let’s walk through what each line does:
async function copyText(text)declares a function markedasyncso we canawaitinside it; it accepts the string we want to copy.await navigator.clipboard.writeText(text)sends the text to the clipboard and pauses the function until that promise resolves.console.log("Text copied:", text)runs only after the copy finishes, confirming the text is now on the clipboard and ready to paste.copyText("Hello, clipboard!")calls the function with a sample string to actually trigger the copy.
📥 Reading Text with readText()
navigator.clipboard.readText() returns a promise that resolves to whatever text is currently on the clipboard. Because it is a promise, you await the result.
async function showClipboard() { const text = await navigator.clipboard.readText(); console.log("Clipboard contains:", text);}
showClipboard();Here is what each line does:
async function showClipboard()declares anasyncfunction so we canawaitthe read inside it.const text = await navigator.clipboard.readText()reads the clipboard and waits for the promise, then stores the resolved string intext.console.log("Clipboard contains:", text)prints whatever the clipboard held.showClipboard()calls the function to run the read.
Reading the clipboard often asks the user for permission. The browser may show a prompt the first time your page tries to read it.
Tie back to async
writeText and readText both return promises, the same promises you learned
about earlier. Mark your function async and await the call so the rest of
your code runs only after the clipboard work is done.
🖱️ A Real Copy Button
Clipboard access must be triggered by a user action, such as a click. The example below wires a “Copy” button to copy a link and then shows a short “Copied!” message.
const button = document.querySelector("#copyButton");const link = "https://www.freecodingschool.com";
button.addEventListener("click", async () => { try { await navigator.clipboard.writeText(link); button.textContent = "Copied!"; setTimeout(() => { button.textContent = "Copy"; }, 2000); } catch (error) { button.textContent = "Failed to copy"; }});Let’s step through the key lines:
const button = document.querySelector("#copyButton")grabs the button element, andconst linkholds the text we want to copy.button.addEventListener("click", async () => {runs theasynchandler on each click, which is the user action the browser requires.await navigator.clipboard.writeText(link)copies the link and waits for the copy to finish.button.textContent = "Copied!"updates the label once the copy succeeds, and thesetTimeoutresets it toCopyafter two seconds.catch (error)runs when the copy is blocked, showingFailed to copyinstead.
🔒 Secure Context Required
The Clipboard API only works in a secure context. That means your page must be served over https, or run on localhost during development. On a plain http page, navigator.clipboard is undefined and the call fails.
Test on localhost
While you build, run your project on localhost, which counts as a secure
context. When you deploy, serve the site over https so the clipboard keeps
working.
⚠️ Common Mistakes to Avoid
| Mistake | Problem | Solution |
| Calling it without a user action | The browser blocks the copy because there was no click or tap | Run it inside an event handler like click |
| Forgetting it returns a promise | Your code continues before the text is actually copied | Mark the function async and await the call |
Expecting it to work on http | navigator.clipboard is undefined outside a secure context | Use https or localhost |
Here is the difference in code:
// ❌ Runs on page load with no user gestureawait navigator.clipboard.writeText("text"); // blocked by the browser
// ✅ Runs inside a click handlerbutton.addEventListener("click", async () => { await navigator.clipboard.writeText("text"); // works});Let’s compare the two halves:
- The first
await navigator.clipboard.writeText("text")fires the moment the page loads, with no click behind it, so the browser blocks it. - The second call lives inside a
clickhandler, so it runs as a direct response to the user’s click, and the browser allows the copy.
🔧 Try It Yourself!
- Add a button to a page and serve the page on
localhost. - In the button’s
clickhandler, callawait navigator.clipboard.writeText(...)to copy a link. - Change the button text to
Copied!after the copy succeeds, then reset it after two seconds. - Add a
readText()call to log the clipboard contents and confirm your text was copied.
🧩 What You’ve Learned
- ✅ The Clipboard API lives on
navigator.clipboard - ✅
writeText(text)copies text andreadText()reads it back - ✅ Both methods return promises, so use
asyncandawait - ✅ Clipboard access must be triggered by a user action like a click
- ✅ The API only works in a secure context (
httpsorlocalhost)
🚀 What’s Next?
Now that you can copy and read clipboard text, we will learn how to find the user’s location in the browser. Let’s continue to Geolocation API.