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.
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.
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
clipboardorclipboard-polyfill. If it runs in a terminal or Electron main process → useclipboardy.
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.
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.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.
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).copy-pasteThe 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.
You’re building a dashboard with a button that copies an API key to the clipboard.
clipboard or clipboard-polyfillclipboard. 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>;
}
You’re writing a Node.js script that generates a config snippet and puts it in the clipboard.
clipboardy#!/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!');
You must support older browsers in a corporate environment.
clipboard-polyfillexecCommand and handles quirks in older browsers better than clipboard.You want users to paste formatted text and capture it.
clipboard-polyfill (for read() support)paste events and extract data from event.clipboardData for full control — but readText() can help in simpler cases.| Package | Environment | Write Text | Read Text | Rich Content | Actively Maintained |
|---|---|---|---|---|---|
clipboard | Browser | ✅ | ❌ | ❌ | ✅ |
clipboard-polyfill | Browser | ✅ | ✅* | ✅ | ✅ |
clipboardy | Node.js | ✅ | ✅ | ❌ | ✅ |
copy-paste | Node.js | ✅ (broken) | ✅ (broken) | ❌ | ❌ (deprecated) |
* readText() requires user gesture and secure context.
clipboard-polyfill. It’s standards-aligned, handles edge cases, and prepares you for future clipboard features.clipboard is acceptable if you don’t need read access or advanced error reporting.clipboardy is the only sane choice.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.
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.
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.
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.
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.
Access the system clipboard (copy/paste)
Cross-platform. Supports: macOS, Windows, Linux (including Wayland), OpenBSD, FreeBSD, Android with Termux, and modern browsers.
npm install clipboardy
import clipboard from 'clipboardy';
await clipboard.write('🦄');
await clipboard.read();
//=> '🦄'
// Or use the synchronous API
clipboard.writeSync('🦄');
clipboard.readSync();
//=> '🦄'
Browser usage: Requires a secure context (HTTPS). Synchronous methods are not available in browsers.
Write (copy) to the clipboard asynchronously.
Returns a Promise<void>.
Type: string
The text to write to the clipboard.
await clipboard.write('🦄');
Read (paste) from the clipboard asynchronously.
Returns a Promise<string>.
const content = await clipboard.read();
//=> '🦄'
Write (copy) to the clipboard synchronously.
Doesn't work in browsers.
Type: string
The text to write to the clipboard.
clipboard.writeSync('🦄');
Read (paste) from the clipboard synchronously.
Returns a string.
Doesn't work in browsers.
const content = clipboard.readSync();
//=> '🦄'
The Linux binary is just a bundled version of xsel. The source for the Windows binary can be found here.
On Windows, clipboardy first tries the native PowerShell cmdlets (Set-Clipboard/Get-Clipboard) and falls back to the bundled binary if PowerShell is unavailable or restricted.
Yes. On Linux, clipboardy automatically detects Wayland sessions and uses wl-clipboard when available. If not, it gracefully falls back to X11 tools. Also works with WSLg (Windows Subsystem for Linux GUI). Install wl-clipboard using your distribution's package manager.