clipboard and copy-paste are npm packages that help developers implement copy-to-clipboard functionality in web applications. Both aim to simplify the process of writing text to the system clipboard, but they differ significantly in architecture, browser support, security model, and use cases. clipboard is a lightweight, browser-only utility built around the modern Clipboard API and legacy document.execCommand(), while copy-paste is a cross-platform module originally designed for Node.js environments with optional browser fallbacks via a DOM shim.
When you need to let users copy text to their clipboard — whether it’s a shareable link, an API key, or a code snippet — you quickly run into browser security restrictions. The two npm packages clipboard and copy-paste both promise to solve this, but they take fundamentally different approaches. Let’s break down how they work, where they succeed, and where they fall short.
clipboard is built exclusively for the browser. It assumes a DOM environment and uses either the modern Clipboard API (which requires user interaction and secure contexts) or falls back to the legacy document.execCommand('copy') method using a temporary <textarea>.
// clipboard: browser-only usage
import ClipboardJS from 'clipboard';
// Attach to a button with data-clipboard-text
new ClipboardJS('.btn-copy');
// Or copy programmatically
const clipboard = new ClipboardJS('.btn', {
text: () => 'Text to copy'
});
copy-paste, by contrast, was originally designed for Node.js and uses platform-specific shell commands (pbcopy on macOS, clip on Windows, xclip or xsel on Linux). In the browser, it includes a fallback that creates a hidden <textarea>, selects its content, and triggers document.execCommand('copy') — but this is not its primary focus.
// copy-paste: works in Node.js or browser (with limitations)
const copyPaste = require('copy-paste');
// In Node.js (relies on OS binaries)
copyPaste.copy('Hello from Node!', () => console.log('Copied!'));
// In browser (uses hidden textarea + execCommand)
copyPaste.copy('Hello from browser!');
⚠️ Important:
copy-paste’s browser implementation does not use the modern Clipboard API and has no mechanism to handle permissions or secure context requirements.
Modern browsers enforce strict rules: you can only write to the clipboard during a user-triggered event (like a click) and only in secure contexts (HTTPS or localhost).
clipboard respects this model:
navigator.clipboard.writeText() when available (async, Promise-based).execCommand only if the Clipboard API isn’t supported.// clipboard handles permissions correctly
const btn = document.querySelector('#copy-btn');
btn.addEventListener('click', () => {
// This works because it's inside a user gesture
navigator.clipboard.writeText('Secure copy');
});
copy-paste ignores these constraints in the browser:
execCommand immediately, regardless of context.setTimeout), it will silently fail in modern browsers.// copy-paste in browser — prone to silent failure
setTimeout(() => {
copyPaste.copy('This likely won’t work'); // No error thrown
}, 1000);
clipboard targets evergreen browsers and gracefully degrades:
execCommand fallback.copy-paste has unreliable browser support:
clipboard provides clear feedback:
const clipboard = new ClipboardJS('.btn');
clipboard.on('success', e => {
console.log('Copied:', e.text);
e.clearSelection();
});
clipboard.on('error', e => {
console.warn('Copy failed. Use Ctrl+C instead.');
});
copy-paste offers minimal error visibility in the browser:
// No standard way to catch failures in browser
copyPaste.copy('text', err => {
// This callback only works in Node.js
if (err) console.error(err);
});
// In browser, errors are silent
clipboard if:copy-paste in browsers. Only consider it if:🚫 Never use
copy-pastein a public-facing website expecting reliable clipboard behavior across devices and browsers.
Imagine you want to copy an API token when a user clicks a button.
With clipboard:
<button class="copy-btn" data-clipboard-text="sk-abc123">Copy Token</button>
<script>
import ClipboardJS from 'clipboard';
new ClipboardJS('.copy-btn');
</script>
This works out of the box, respects user gestures, and degrades gracefully.
With copy-paste in browser:
<button id="copy-btn">Copy Token</button>
<script>
const copyPaste = require('copy-paste');
document.getElementById('copy-btn').addEventListener('click', () => {
copyPaste.copy('sk-abc123'); // May fail silently on iOS or in secure contexts
});
</script>
This might work on desktop Chrome today, but will likely break on iOS Safari or in stricter browser versions.
For frontend web development, clipboard is the clear, responsible choice. It’s purpose-built for the browser, aligns with web standards, and handles real-world edge cases.
copy-paste serves a niche in server-side or desktop Node.js applications, but its browser implementation is outdated and should not be used in production web apps. If you see it in a frontend codebase, plan to migrate to clipboard or the native navigator.clipboard API.
💡 Pro Tip: For simple cases, you might not even need a library. Modern browsers support
navigator.clipboard.writeText()directly — just remember to wrap it in a user gesture and provide a fallback for older browsers.
async function copyText(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Copied!');
} catch (err) {
// Fallback to legacy method
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
}
Choose clipboard if you're building a frontend-only web application that runs in modern browsers and needs reliable, secure clipboard access without server-side or Node.js dependencies. It works well with frameworks like React, Vue, or vanilla JS, integrates cleanly with user gestures (like button clicks), and follows current web standards by leveraging the asynchronous Clipboard API when available. Avoid it if you need clipboard access outside the browser context.
Choose copy-paste only if you require clipboard operations in a Node.js environment (e.g., CLI tools or Electron apps with Node integration) and can accept its reliance on native OS commands (pbcopy, xclip, etc.). In browser contexts, it uses a hidden textarea workaround that may not comply with modern security policies and lacks support for the standard Clipboard API. Note that its browser support is limited and unmaintained for pure web use cases.
Modern copy to clipboard. No Flash. Just 3kb gzipped.
Copying text to the clipboard shouldn't be hard. It shouldn't require dozens of steps to configure or hundreds of KBs to load. But most of all, it shouldn't depend on Flash or any bloated framework.
That's why clipboard.js exists.
You can get it on npm.
npm install clipboard --save
Or if you're not into package management, just download a ZIP file.
First, include the script located on the dist folder or load it from a third-party CDN provider.
<script src="dist/clipboard.min.js"></script>
Now, you need to instantiate it by passing a DOM selector, HTML element, or list of HTML elements.
new ClipboardJS('.btn');
Internally, we need to fetch all elements that matches with your selector and attach event listeners for each one. But guess what? If you have hundreds of matches, this operation can consume a lot of memory.
For this reason we use event delegation which replaces multiple event listeners with just a single listener. After all, #perfmatters.
We're living a declarative renaissance, that's why we decided to take advantage of HTML5 data attributes for better usability.
A pretty common use case is to copy content from another element. You can do that by adding a data-clipboard-target attribute in your trigger element.
The value you include on this attribute needs to match another's element selector.
<!-- Target -->
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git" />
<!-- Trigger -->
<button class="btn" data-clipboard-target="#foo">
<img src="assets/clippy.svg" alt="Copy to clipboard" />
</button>
Additionally, you can define a data-clipboard-action attribute to specify if you want to either copy or cut content.
If you omit this attribute, copy will be used by default.
<!-- Target -->
<textarea id="bar">Mussum ipsum cacilds...</textarea>
<!-- Trigger -->
<button class="btn" data-clipboard-action="cut" data-clipboard-target="#bar">
Cut to clipboard
</button>
As you may expect, the cut action only works on <input> or <textarea> elements.
Truth is, you don't even need another element to copy its content from. You can just include a data-clipboard-text attribute in your trigger element.
<!-- Trigger -->
<button
class="btn"
data-clipboard-text="Just because you can doesn't mean you should — clipboard.js"
>
Copy to clipboard
</button>
There are cases where you'd like to show some user feedback or capture what has been selected after a copy/cut operation.
That's why we fire custom events such as success and error for you to listen and implement your custom logic.
var clipboard = new ClipboardJS('.btn');
clipboard.on('success', function (e) {
console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);
e.clearSelection();
});
clipboard.on('error', function (e) {
console.error('Action:', e.action);
console.error('Trigger:', e.trigger);
});
For a live demonstration, go to this site and open your console.
Each application has different design needs, that's why clipboard.js does not include any CSS or built-in tooltip solution.
The tooltips you see on the demo site were built using GitHub's Primer. You may want to check that out if you're looking for a similar look and feel.
If you don't want to modify your HTML, there's a pretty handy imperative API for you to use. All you need to do is declare a function, do your thing, and return a value.
For instance, if you want to dynamically set a target, you'll need to return a Node.
new ClipboardJS('.btn', {
target: function (trigger) {
return trigger.nextElementSibling;
},
});
If you want to dynamically set a text, you'll return a String.
new ClipboardJS('.btn', {
text: function (trigger) {
return trigger.getAttribute('aria-label');
},
});
For use in Bootstrap Modals or with any other library that changes the focus you'll want to set the focused element as the container value.
new ClipboardJS('.btn', {
container: document.getElementById('modal'),
});
Also, if you are working with single page apps, you may want to manage the lifecycle of the DOM more precisely. Here's how you clean up the events and objects that we create.
var clipboard = new ClipboardJS('.btn');
clipboard.destroy();
This library relies on both Selection and execCommand APIs. The first one is supported by all browsers while the second one is supported in the following browsers.
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
|---|---|---|---|---|---|
| 42+ ✔ | 12+ ✔ | 41+ ✔ | 9+ ✔ | 29+ ✔ | 10+ ✔ |
The good news is that clipboard.js gracefully degrades if you need to support older browsers. All you have to do is show a tooltip saying Copied! when success event is called and Press Ctrl+C to copy when error event is called because the text is already selected.
You can also check if clipboard.js is supported or not by running ClipboardJS.isSupported(), that way you can hide copy/cut buttons from the UI.
A browser extension that adds a "copy to clipboard" button to every code block on GitHub, MDN, Gist, StackOverflow, StackExchange, npm, and even Medium.
Install for Chrome and Firefox.
MIT License © Zeno Rocha