clipboard vs clipboard-polyfill vs clipboardy vs copy-paste
Client-Side Clipboard Interaction in Web Applications
clipboardclipboard-polyfillclipboardycopy-pasteSimilar Packages:

Client-Side Clipboard Interaction in Web Applications

clipboard, clipboard-polyfill, clipboardy, and copy-paste are npm packages that provide programmatic access to the system clipboard in JavaScript environments. They address the challenge of copying text (and sometimes other data) to the user's clipboard across different browsers and execution contexts — from browser-based frontend apps to Node.js scripts. Each package targets distinct runtime environments and use cases: some focus exclusively on modern browser APIs with graceful fallbacks, others support both browser and Node.js, while one is strictly for Node.js command-line or server-side usage. Understanding their scope, API design, and environment compatibility is essential for making the right architectural choice.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
clipboard034,18294.5 kB15-MIT
clipboard-polyfill0927404 kB9a year agoMIT
clipboardy01,942873 kB04 hours agoMIT
copy-paste044817 kB87 months ago-

Client-Side Clipboard Interaction: clipboard vs clipboard-polyfill vs clipboardy vs copy-paste

Copying and pasting data programmatically seems simple, but browser security restrictions, API inconsistencies, and environment differences make it surprisingly tricky. The four packages under review each tackle this problem differently — some for browsers, some for Node.js, and one that’s past its prime. Let’s cut through the noise and see which tool fits your real-world scenario.

🖥️ Runtime Environment: Browser vs Node.js

This is the first and most critical filter. Not all clipboard packages work everywhere.

clipboard and clipboard-polyfill are browser-only. They rely on DOM APIs like document.execCommand() or navigator.clipboard and will throw errors if used in Node.js.

clipboardy is Node.js-only. It uses platform-specific commands (pbcopy/pbpaste on macOS, clip/powershell on Windows, xclip/xsel on Linux) via child processes. It cannot run in a browser.

copy-paste was also designed for Node.js, but it’s deprecated — more on that later.

💡 Rule of thumb: If your code runs in a browser tab → use clipboard or clipboard-polyfill. If it runs in a terminal or Electron main process → use clipboardy.

✂️ Basic Copy Operation: How Each Package Writes Text

Let’s look at the simplest common task: copying a string to the clipboard.

clipboard (browser)

Designed as a minimal wrapper. You create an instance tied to a DOM element (usually a button), and it handles the rest:

import ClipboardJS from 'clipboard';

// Attach to a button with data-clipboard-text
const btn = document.querySelector('#copy-btn');
const clipboard = new ClipboardJS(btn);

// Or specify text dynamically
const clipboard2 = new ClipboardJS('.btn', {
  text: () => 'Hello, clipboard!'
});

clipboard2.on('success', e => {
  console.log('Copied:', e.text);
  e.clearSelection();
});

It automatically chooses between navigator.clipboard.writeText() (modern) and document.execCommand('copy') (legacy).

clipboard-polyfill (browser)

Provides a function-based API that mimics the standard Clipboard API, with built-in polyfill logic:

import { writeText } from 'clipboard-polyfill';

async function copyToClipboard() {
  try {
    await writeText('Hello, clipboard!');
    console.log('Copied successfully');
  } catch (err) {
    console.error('Failed to copy:', err);
  }
}

// Must be called in response to a user gesture (e.g., click handler)
document.getElementById('copy-btn').addEventListener('click', copyToClipboard);

Under the hood, it handles permission requests, iframe sandboxing, and fallbacks seamlessly.

clipboardy (Node.js)

Simple promise-based API for scripts:

import { write } from 'clipboardy';

await write('Hello, clipboard!');
console.log('Text copied to system clipboard');

Works in any Node.js context — great for CLI tools that need to output something directly to the clipboard.

copy-paste (Node.js, deprecated)

Used a callback-style API:

// ⚠️ DO NOT USE — shown for reference only
const copyPaste = require('copy-paste');

copyPaste.copy('Hello, clipboard!', () => {
  console.log('Copied');
});

But this package is no longer maintained and fails on newer OS versions due to changes in clipboard utilities.

🔍 Reading from the Clipboard

Not all packages support reading clipboard content — and for good reason: browsers restrict read access for security.

  • clipboard: ❌ Does not support reading. Only writing.
  • clipboard-polyfill: ✅ Supports reading via readText(), but only in secure contexts (HTTPS) and only when triggered by a user gesture. Falls back gracefully where unsupported.
import { readText } from 'clipboard-polyfill';

async function readFromClipboard() {
  try {
    const text = await readText();
    console.log('Pasted:', text);
  } catch (err) {
    console.error('Read failed:', err);
  }
}
  • clipboardy: ✅ Full read/write support in Node.js:
import { read, write } from 'clipboardy';

await write('test');
const content = await read(); // returns 'test'
  • copy-paste: Supported reading via paste(), but again — deprecated and unreliable.

🛡️ Security and User Gesture Requirements

Browsers require clipboard write operations to occur within a user-initiated event (like a click). All browser packages respect this, but they handle violations differently.

  • clipboard: Silently fails if not triggered by a user action. No error thrown in legacy mode.
  • clipboard-polyfill: Throws a clear error in development if called outside a user gesture, helping catch bugs early.
  • clipboardy: No such restriction in Node.js — you can read/write anytime.

Also, clipboard-polyfill properly handles the Permissions API for clipboard access in modern browsers, requesting permission when needed.

🧩 Advanced Features: HTML, Images, Custom Formats

Most apps only need plain text, but some require richer content.

  • clipboard: Plain text only. No support for HTML or other formats.
  • clipboard-polyfill: Supports writing HTML and custom MIME types via write():
import { write } from 'clipboard-polyfill';

const dt = new DataTransfer();
dt.setData('text/plain', 'Fallback text');
dt.setData('text/html', '<b>Bold text</b>');

await write(dt);

This aligns with the official Clipboard API spec.

  • clipboardy: Plain text only. Binary or rich content isn’t supported.
  • copy-paste: Plain text only (and broken).

🚫 Deprecation Warning: Avoid copy-paste

The copy-paste package has been deprecated by its author. Its last update was years ago, it uses unsafe child_process.exec calls without proper escaping, and it fails on modern systems (e.g., macOS Sonoma removed pbcopy from default PATH in some contexts). The README now recommends using clipboardy instead. Do not use copy-paste in new projects.

🧪 Real-World Decision Guide

Scenario 1: “Copy” Button in a React App

You’re building a dashboard with a button that copies an API key to the clipboard.

  • Best choice: clipboard or clipboard-polyfill
  • Why? Both work in browsers. If you only need plain text and want minimal bundle impact → clipboard. If you need better error handling, future-proofing, or plan to read clipboard later → clipboard-polyfill.
// With clipboard-polyfill (recommended for new apps)
import { writeText } from 'clipboard-polyfill';

function CopyButton({ text }) {
  const handleClick = () => writeText(text);
  return <button onClick={handleClick}>Copy</button>;
}

Scenario 2: CLI Tool That Copies Output to Clipboard

You’re writing a Node.js script that generates a config snippet and puts it in the clipboard.

  • Best choice: clipboardy
  • Why? It’s the only actively maintained, reliable option for Node.js.
#!/usr/bin/env node
import { write } from 'clipboardy';

const config = `API_KEY=${process.env.API_KEY}`;
await write(config);
console.log('Config copied to clipboard!');

Scenario 3: Enterprise Web App Supporting IE11

You must support older browsers in a corporate environment.

  • Best choice: clipboard-polyfill
  • Why? It includes robust fallbacks for execCommand and handles quirks in older browsers better than clipboard.

Scenario 4: Reading Pasted Content in a Rich Text Editor

You want users to paste formatted text and capture it.

  • Best choice: clipboard-polyfill (for read() support)
  • Note: You’ll still need to listen to paste events and extract data from event.clipboardData for full control — but readText() can help in simpler cases.

📊 Summary Table

PackageEnvironmentWrite TextRead TextRich ContentActively Maintained
clipboardBrowser
clipboard-polyfillBrowser✅*
clipboardyNode.js
copy-pasteNode.js✅ (broken)✅ (broken)❌ (deprecated)

* readText() requires user gesture and secure context.

💡 Final Recommendation

  • For modern browser apps: Use clipboard-polyfill. It’s standards-aligned, handles edge cases, and prepares you for future clipboard features.
  • For simple browser copy buttons with minimal footprint: clipboard is acceptable if you don’t need read access or advanced error reporting.
  • For Node.js or CLI tools: clipboardy is the only sane choice.
  • Never use copy-paste — it’s a relic.

Choose based on your runtime first, then your feature needs. Don’t overcomplicate it — most web apps only need to write plain text, and both clipboard and clipboard-polyfill do that well. But if you care about maintainability and forward compatibility, clipboard-polyfill is the smarter long-term bet for browser-based clipboard interaction.

How to Choose: clipboard vs clipboard-polyfill vs clipboardy vs copy-paste

  • clipboard:

    Choose clipboard if you're building a browser-based UI component (like a 'copy' button) and want a lightweight, zero-dependency wrapper around the modern navigator.clipboard API with automatic fallback to legacy execCommand for older browsers. It’s ideal for simple copy operations triggered by user gestures in web apps, but it doesn’t support reading from the clipboard or Node.js environments.

  • clipboard-polyfill:

    Choose clipboard-polyfill if you need robust cross-browser clipboard write (and limited read) support with automatic feature detection and polyfilling, including handling of permissions and sandboxed iframes. It’s well-suited for applications that must work reliably in enterprise environments with older browsers or strict security policies, and it supports writing plain text, HTML, and custom formats via the standard Clipboard API shape.

  • clipboardy:

    Choose clipboardy if you’re writing scripts or tools that run in Node.js (e.g., CLI utilities, build scripts, or Electron main processes) and need to interact with the system clipboard outside the browser. It does not work in browser environments and should never be bundled into frontend code. It supports both reading and writing clipboard content on macOS, Windows, and Linux.

  • copy-paste:

    Avoid copy-paste in new projects — it is deprecated and unmaintained. The package hasn’t been updated in years, relies on outdated Node.js child process patterns, and lacks support for modern security practices. Use clipboardy instead for Node.js clipboard needs.

README for clipboard

clipboard.js

Build Status Killing Flash

Modern copy to clipboard. No Flash. Just 3kb gzipped.

Demo

Why

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.

Install

You can get it on npm.

npm install clipboard --save

Or if you're not into package management, just download a ZIP file.

Setup

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.

Usage

We're living a declarative renaissance, that's why we decided to take advantage of HTML5 data attributes for better usability.

Copy text from another element

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.

example-2

<!-- 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>

Cut text from another element

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.

example-3

<!-- 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.

Copy text from attribute

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.

example-1

<!-- Trigger -->
<button
  class="btn"
  data-clipboard-text="Just because you can doesn't mean you should — clipboard.js"
>
  Copy to clipboard
</button>

Events

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.

Tooltips

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.

Advanced Options

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();

Browser Support

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.

Chrome logoEdge logoFirefox logoInternet Explorer logoOpera logoSafari logo
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.

Bonus

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.

License

MIT License © Zeno Rocha