clipboard、clipboard-polyfill、copy-to-clipboard、react-copy-to-clipboard、vue-clipboard2 はすべて、Web アプリケーションからユーザーのシステムクリップボードにテキストをコピーする機能を提供する npm パッケージです。これらのライブラリは、document.execCommand('copy') のような古い API や、現代の navigator.clipboard.writeText() Web API をラップまたはポリフィルすることで、クロスブラウザで安全かつ信頼性の高いコピー動作を実現します。各パッケージは異なる設計哲学と統合戦略を持っており、特にフレームワーク依存性(React/Vue 向け vs フレームワーク非依存)、ポリフィルの必要性、API の使いやすさにおいて差異があります。
Web アプリで「コピー」ボタンを実装するのは一見簡単ですが、実際にはブラウザのセキュリティ制限、API の進化、フレームワークとの統合など、多くの技術的課題があります。この記事では、代表的な5つの npm パッケージを、実際のコードと開発シナリオに基づいて深く比較します。
まず、最も単純なケース —— 任意の文字列をプログラムでコピーする —— で各ライブラリの使い勝手を確認します。
clipboard は DOM 要素に依存するため、直接文字列を渡せません。代わりに、data-clipboard-text 属性を持つ要素が必要です。
// clipboard: DOM 要素必須
import Clipboard from 'clipboard';
const btn = document.createElement('button');
btn.setAttribute('data-clipboard-text', 'Hello, world!');
document.body.appendChild(btn);
new Clipboard(btn);
// ボタンクリックでコピーされる(プログラムによる即時コピー不可)
clipboard-polyfill は Promise ベースのシンプルな関数呼び出しで動作します。
// clipboard-polyfill
import { writeText } from 'clipboard-polyfill';
writeText('Hello, world!').catch(err => console.error(err));
copy-to-clipboard も同様に、関数1つでコピー可能です。
// copy-to-clipboard
import copy from 'copy-to-clipboard';
copy('Hello, world!'); // boolean を返す(成功/失敗)
react-copy-to-clipboard は React コンポーネントとして使用します。
// react-copy-to-clipboard
import { CopyToClipboard } from 'react-copy-to-clipboard';
function App() {
return (
<CopyToClipboard text="Hello, world!">
<button>コピー</button>
</CopyToClipboard>
);
}
vue-clipboard2 は Vue ディレクティブでバインドします(Vue 2 限定)。
// vue-clipboard2 (Vue 2)
import Vue from 'vue';
import VueClipboard from 'vue-clipboard2';
Vue.use(VueClipboard);
// テンプレート内
// <button v-clipboard:copy="'Hello, world!'">コピー</button>
💡 ポイント:
clipboard以外は、DOM 要素を介さずに直接文字列をコピーできます。ただし、react-copy-to-clipboardとvue-clipboard2はそれぞれのフレームワークに強く依存しています。
現代のブラウザでは、navigator.clipboard.writeText() が標準ですが、これは HTTPS または localhost でのみ動作します。一方、古い document.execCommand('copy') は任意のコンテキストで動作しますが、非推奨です。
clipboard は execCommand のみ を使用します。そのため、最新ブラウザでも非推奨 API に依存し続けます。
clipboard-polyfill は Clipboard API を優先し、サポートされていない環境では execCommand にフォールバックします。さらに、iOS Safari の特殊な挙動にも対応しています。
copy-to-clipboard も同様に、モダン API を優先し、必要に応じて execCommand にフォールバックします。
react-copy-to-clipboard は内部で copy-to-clipboard を使用しているため、同じ互換性戦略を持ちます。
vue-clipboard2 は clipboard ライブラリに依存しており、execCommand のみ を使用します。
⚠️ 注意:
clipboardとvue-clipboard2は非推奨 API に依存しているため、新しいプロジェクトでは避けるべきです。特に、モバイル Safari や今後のブラウザアップデートで動作しなくなるリスクがあります。
コピー操作は常に成功するとは限りません(例: ユーザーが権限を拒否した場合)。各ライブラリのエラー処理方法を比較します。
clipboard-polyfill は Promise を返すため、catch でエラーを捕捉できます。
writeText('text').catch(err => {
console.error('コピー失敗:', err.message);
});
copy-to-clipboard は成功時に true、失敗時に false を返します。
const success = copy('text');
if (!success) {
console.warn('コピーに失敗しました');
}
clipboard と vue-clipboard2 はイベントリスナー経由で結果を取得します。
const clipboard = new Clipboard(btn);
clipboard.on('error', e => console.error('コピー失敗'));
react-copy-to-clipboard は onCopy コールバックで結果を通知します。
<CopyToClipboard text="text" onCopy={(text, result) => {
if (!result) console.warn('コピー失敗');
}}>
<button>コピー</button>
</CopyToClipboard>
💡 実践的アドバイス: Promise ベースの
clipboard-polyfillは非同期処理との統合が容易で、モダンなコードベースに適しています。一方、copy-to-clipboardの boolean 返り値はシンプルで直感的です。
react-copy-to-clipboard は JSX に自然に組み込めますが、カスタムロジック(例: 成功時のトースト表示)を追加するには onCopy を使う必要があります。copy-to-clipboard を直接使うと、より柔軟な制御が可能です。// copy-to-clipboard を React で使う例
import { useState } from 'react';
import copy from 'copy-to-clipboard';
function CopyButton({ text }) {
const [copied, setCopied] = useState(false);
const handleClick = () => {
if (copy(text)) {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
};
return <button onClick={handleClick}>{copied ? 'コピー済み' : 'コピー'}</button>;
}
vue-clipboard2 は Vue 2 専用であり、Vue 3 では動作しません。Vue 3 プロジェクトでは、copy-to-clipboard を Composition API でラップするのが現実的です。// Vue 3 + copy-to-clipboard の例
import { ref } from 'vue';
import copy from 'copy-to-clipboard';
export function useClipboard() {
const copied = ref(false);
const copyText = (text) => {
if (copy(text)) {
copied.value = true;
setTimeout(() => copied.value = false, 2000);
}
};
return { copied, copyText };
}
公式情報によると:
clipboard は GitHub リポジトリで「このプロジェクトはメンテナンスされていません」と明記されており、新しいプロジェクトでの使用は推奨されません。vue-clipboard2 は Vue 3 に対応しておらず、最終更新が古いため、Vue 2 レガシープロジェクト以外では避けるべきです。一方、clipboard-polyfill と copy-to-clipboard は積極的にメンテナンスされており、最新のブラウザ変更にも追随しています。
| ライブラリ | 推奨用途 | フレームワーク依存 | モダン API 対応 | 新規プロジェクト向け |
|---|---|---|---|---|
clipboard | レガシーな静的サイト | なし | ❌ | ❌ |
clipboard-polyfill | クロスブラウザ対応が必要な汎用アプリ | なし | ✅(ポリフィル付き) | ✅ |
copy-to-clipboard | シンプルで軽量なコピー機能 | なし | ✅(自動フォールバック) | ✅ |
react-copy-to-clipboard | React 専用の簡易実装 | React | ✅(内部で copy-to-clipboard 使用) | △(小規模向け) |
vue-clipboard2 | Vue 2 レガシープロジェクト | Vue 2 | ❌ | ❌ |
clipboard-polyfill(完全なポリフィル)または copy-to-clipboard(軽量)react-copy-to-clipboard(ただし、カスタムロジックが必要なら copy-to-clipboard 直接使用が柔軟)copy-to-clipboard を Composition API でラップclipboard や vue-clipboard2 を使うのは避けてください。非推奨 API への依存は将来的な破壊的変更を招きます。クリップボード操作は「小さな機能」に見えますが、ユーザー体験に直結します。信頼性と将来性を考えて、適切なツールを選びましょう。
clipboard は DOM 要素に直接バインドして動作する軽量なライブラリです。ボタンクリックなどのイベント発火時に特定の要素の内容や属性値をコピーしたい場合に最適です。ただし、execCommand に依存しており、モダンな Clipboard API には対応していません。新しいプロジェクトでは、セキュリティ制限や非推奨化のリスクを考慮し、代替手段を検討すべきです。
clipboard-polyfill は navigator.clipboard.writeText() の完全なポリフィルを提供し、古いブラウザでも動作するように設計されています。フレームワークに依存せず、純粋な JavaScript 環境で一貫した API を使いたい場合に最適です。特に、セキュリティコンテキスト(HTTPS や localhost)外でも動作させる必要があるレガシー環境向けに有用ですが、最新ブラウザのみをターゲットにする場合はオーバーヘッドになる可能性があります。
copy-to-clipboard はシンプルな関数ベースの API を持ち、任意の文字列をコピーするための最小限のユーティリティです。React や Vue などのフレームワークに依存せず、軽量で直感的に使用できます。モダンブラウザでは Clipboard API を、古い環境では execCommand を内部で自動的に切り替えて使用するため、バランスの取れた選択肢です。複雑な DOM 操作やトリガー要素不要なケースに最適です。
react-copy-to-clipboard は React 専用のコンポーネントとして設計されており、JSX 内で宣言的にコピー機能を実装できます。<CopyToClipboard> コンポーネントに text プロパティを渡すだけで、子要素のクリックでコピーが発火します。React プロジェクトで迅速にコピー UI を実装したい場合に便利ですが、React 以外の環境では使用できません。内部では copy-to-clipboard パッケージを利用しています。
vue-clipboard2 は Vue 2 向けのディレクティブ (v-clipboard) を提供し、Vue コンポーネント内で簡単にクリップボード機能をバインドできます。Vue 2 プロジェクトで既存のボタンや要素にコピー動作を追加したい場合に最適です。ただし、Vue 3 には正式に対応しておらず、メンテナンス状況を確認する必要があります。新しい Vue プロジェクトでは、代わりに @vueuse/core の useClipboard などを検討すべきです。
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="https://raw.githubusercontent.com/zenorocha/clipboard.js/HEAD/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