clipboard vs clipboard-polyfill vs copy-to-clipboard vs react-copy-to-clipboard vs vue-clipboard2
Copying Text to Clipboard in Web Applications
clipboardclipboard-polyfillcopy-to-clipboardreact-copy-to-clipboardvue-clipboard2Similar Packages:

Copying Text to Clipboard in Web Applications

clipboard, clipboard-polyfill, copy-to-clipboard, react-copy-to-clipboard, and vue-clipboard2 are JavaScript libraries that simplify copying text to the system clipboard across different browsers and environments. They abstract away the complexities of the native document.execCommand('copy') API (now deprecated) and the modern asynchronous navigator.clipboard.writeText() API, handling fallbacks, permissions, and browser inconsistencies. These packages differ significantly in scope: some are framework-agnostic utilities (clipboard, clipboard-polyfill, copy-to-clipboard), while others provide React or Vue-specific bindings (react-copy-to-clipboard, vue-clipboard2).

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
clipboard034,17094.5 kB15-MIT
clipboard-polyfill0928404 kB9a year agoMIT
copy-to-clipboard01,39715.1 kB47-MIT
react-copy-to-clipboard02,37137.9 kB14a month agoMIT
vue-clipboard201,759-375 years agoMIT

Copying Text to Clipboard: A Practical Guide for Frontend Engineers

Copying text to the clipboard seems simple, but browser inconsistencies, security restrictions, and the deprecation of execCommand make it surprisingly tricky. The five packages under review tackle this problem differently — from DOM-centric helpers to modern promise-based utilities and framework wrappers. Let’s cut through the noise and see which tool fits your architecture.

⚠️ Critical Maintenance Note

Before diving in, note that vue-clipboard2 is officially deprecated. Its GitHub repository and npm page state: "This package is no longer maintained. Please use @soerenmartius/vue3-clipboard instead." Do not use it in new projects. We’ll still cover it briefly for legacy context, but treat it as a cautionary tale.

🧩 Core Approach: How Each Package Solves the Problem

clipboard: Declarative DOM Binding

clipboard attaches copy behavior directly to HTML elements using data attributes. You never call a function — just add attributes like data-clipboard-text to a button, and the library handles the rest on click.

<!-- HTML setup -->
<button id="btn" data-clipboard-text="Hello World">Copy</button>
// JS initialization
import ClipboardJS from 'clipboard';
new ClipboardJS('#btn');

It listens for clicks, extracts text from attributes, and attempts to copy. Works only in response to user gestures (required by browser security).

clipboard-polyfill: Standards-Based Promise API

clipboard-polyfill provides a clean, modern interface aligned with the official navigator.clipboard API. It returns promises and handles fallbacks internally.

import { writeText } from 'clipboard-polyfill';

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

It automatically uses navigator.clipboard.writeText() when available and falls back to legacy methods (with proper sandboxing) in older browsers. Also works in non-DOM environments like Web Workers.

copy-to-clipboard: Minimalist Function

copy-to-clipboard exports a single synchronous function that tries to copy text and returns a boolean success status.

import copy from 'copy-to-clipboard';

function handleClick() {
  const success = copy('Hello World');
  if (success) {
    console.log('Copied!');
  }
}

No promises, no callbacks — just fire-and-forget. Internally, it uses a temporary textarea element to perform the copy operation.

react-copy-to-clipboard: React Component Wrapper

This package wraps copy-to-clipboard in a React component. You render it with text and onCopy props, and it clones its child with extra props.

import { CopyToClipboard } from 'react-copy-to-clipboard';

function App() {
  return (
    <CopyToClipboard text="Hello World" onCopy={() => console.log('Copied!')}>
      <button>Copy</button>
    </CopyToClipboard>
  );
}

Under the hood, it calls copy-to-clipboard when the child element is clicked.

vue-clipboard2: Deprecated Vue Directive

Historically, this provided a Vue directive for copying:

// ❌ DO NOT USE — deprecated
import VueClipboard from 'vue-clipboard2';
Vue.use(VueClipboard);
<template>
  <button v-clipboard:copy="'Hello World'">Copy</button>
</template>

But again — this package is unmaintained and should be avoided.

🔒 Security and Browser Support Realities

All these libraries must contend with two hard constraints:

  1. User gesture requirement: Browsers only allow clipboard writes during direct user actions (click, keypress). No library can bypass this.
  2. Permission model: Modern browsers (Chrome, Edge) require permission for navigator.clipboard outside of secure contexts.

Here’s how they handle it:

  • clipboard: Only works on click events. Fails silently in unsupported contexts.
  • clipboard-polyfill: Uses the standard permission API when possible. Throws clear errors when blocked, and includes a shouldShowPermissionPrompt() helper.
  • copy-to-clipboard: Tries to copy immediately. Returns false if blocked, but gives no details why.
  • react-copy-to-clipboard: Inherits copy-to-clipboard’s behavior — no error context.
  • vue-clipboard2: Same as clipboard — gesture-bound with minimal error feedback.

🧪 Programmatic vs Declarative Usage

Your choice depends heavily on whether you prefer programmatic control (calling functions from JS) or declarative binding (attaching behavior via HTML/JSX).

When you need programmatic control:

  • Use clipboard-polyfill if you want modern promise handling and detailed error reporting.
  • Use copy-to-clipboard if you just need a fire-and-forget boolean result.
// clipboard-polyfill: async/await with error details
try {
  await writeText(text);
} catch (err) {
  if (err.name === 'NotAllowedError') {
    showPermissionGuide();
  }
}

// copy-to-clipboard: simple boolean
if (!copy(text)) {
  alert('Copy failed — try manually');
}

When you prefer declarative markup:

  • Use clipboard for vanilla JS/jQuery apps with static buttons.
  • Use react-copy-to-clipboard if you’re in React and like component composition.
<!-- clipboard: pure HTML -->
<button data-clipboard-text="...">Copy</button>
{/* react-copy-to-clipboard: JSX */}
<CopyToClipboard text="..."><button>Copy</button></CopyToClipboard>

🌐 Framework Integration Trade-offs

  • React users: react-copy-to-clipboard feels natural but adds an extra dependency layer. Many teams skip it and call clipboard-polyfill directly inside event handlers for more control.
// Common React pattern without wrapper
function CopyButton({ text }) {
  const handleCopy = async () => {
    try {
      await writeText(text);
      // update UI state, etc.
    } catch (err) { /* handle */ }
  };
  return <button onClick={handleCopy}>Copy</button>;
}
  • Vue users: Since vue-clipboard2 is dead, the best path is using clipboard-polyfill directly in methods:
// Vue 3 Composition API example
import { writeText } from 'clipboard-polyfill';

export default {
  methods: {
    async copyText(text) {
      try {
        await writeText(text);
        // handle success
      } catch (err) {
        // handle error
      }
    }
  }
};
  • Framework-agnostic apps: clipboard-polyfill is the safest bet for new projects. It’s actively maintained, follows web standards, and works everywhere from SPAs to Web Workers.

📋 Feature Comparison Summary

PackageAPI StyleAsync SupportError DetailsFramework-SpecificMaintenance Status
clipboardDeclarative DOMNone✅ Active
clipboard-polyfillProgrammatic✅ PromiseNone✅ Active
copy-to-clipboardProgrammatic❌ (boolean)None✅ Active
react-copy-to-clipboardReact ComponentReact✅ Active
vue-clipboard2Vue DirectiveVue 2Deprecated

💡 Final Recommendation

  • For new projects: Use clipboard-polyfill. It’s the most future-proof, gives you detailed error handling, and aligns with web standards. Call it directly from your framework’s event handlers.
  • For simple utility needs: If you don’t care about error details and just want a one-liner, copy-to-clipboard is fine.
  • For legacy jQuery-style apps: clipboard works well if you’re already using data attributes extensively.
  • For React: Skip react-copy-to-clipboard unless you strongly prefer its component API — most teams gain more flexibility by using clipboard-polyfill directly.
  • For Vue: Avoid vue-clipboard2 entirely. Use clipboard-polyfill in methods or composables.

Remember: no library can bypass browser security. Always design your UI to handle copy failures gracefully — show a fallback tooltip, highlight the text for manual selection, or guide users through permission prompts when needed.

How to Choose: clipboard vs clipboard-polyfill vs copy-to-clipboard vs react-copy-to-clipboard vs vue-clipboard2

  • clipboard:

    Choose clipboard if you need a DOM-focused utility that binds copy behavior directly to HTML elements via data attributes, and your app uses buttons or other interactive elements where declarative markup is preferred. It’s ideal for simple static sites or jQuery-style apps but requires manual DOM setup and doesn’t support programmatic copying outside of user-triggered events.

  • clipboard-polyfill:

    Choose clipboard-polyfill if you require a lightweight, modern, framework-agnostic solution that prioritizes standards compliance and works reliably in both browser and non-browser environments (like Web Workers). It supports both promise-based and callback APIs, handles permission prompts gracefully, and actively maintains compatibility with the latest web standards.

  • copy-to-clipboard:

    Choose copy-to-clipboard if you want the simplest possible function-based API for programmatic copying without any DOM coupling. It’s a good fit for utility-heavy applications where you trigger copies from JavaScript logic rather than HTML attributes, and you prefer minimal abstraction over feature richness.

  • react-copy-to-clipboard:

    Choose react-copy-to-clipboard only if you’re working in a React codebase and prefer a component-based API that integrates naturally with JSX. Note that it wraps copy-to-clipboard under the hood, so it inherits its simplicity but adds React-specific ergonomics like render props or children-as-function patterns.

  • vue-clipboard2:

    Avoid vue-clipboard2 in new projects — it is officially deprecated as of 2021 and unmaintained. The author recommends migrating to @soerenmartius/vue3-clipboard for Vue 3 or using a framework-agnostic alternative like clipboard-polyfill. Do not use it for production applications due to lack of updates and security patches.

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="https://raw.githubusercontent.com/zenorocha/clipboard.js/HEAD/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