剪贴板操作必须在用户手势(如点击事件)中调用,部分浏览器每次手势只允许一次操作;IE 下需自行 polyfill window.Promise;多数浏览器只支持写入 text/plain 和 text/html,不支持的类型可能被静默丢弃或抛错
clipboard-polyfill
lgarron长期未更新提供跨浏览器兼容的剪贴板复制粘贴 API,封装异步 Clipboard 接口并兼容旧版浏览器,适合需要兼容老旧环境的 Web 项目。
:clipboard: Simple copying on the web, with maximum browser compatibility. (You probably don't need this anymore!)
让网页复制在所有浏览器都能用的异步剪贴板 API 兼容层,如今多数场景已不需要
提供跨浏览器兼容的剪贴板复制粘贴 API,封装异步 Clipboard 接口并兼容旧版浏览器,适合需要兼容老旧环境的 Web 项目。
核心能力
- 提供 Promise 版 writeText/readText 复制文本
- 支持用 ClipboardItem 写入 text/html 富文本
- 可导入 overwrite-globals 覆盖全局剪贴板 API
- 提供含 Promise 的 ES5 单文件供 script 直接引入
- 兼容到 IE9 等老浏览器并绕过历史兼容 bug
容易踩的坑
- v4.1.1最新正式版2024-12-14 · 2024-12-14 01:44 UTC
Release notes:
- Add a
"default"field to the package `"exports". This may increase compatibility with some ecosystem tools.
- Add a
- v4.1.02024-04-24 · 2024-04-24 09:42 UTC
查看更新说明
Release notes:
- Fix an issue where the contents of a
NotAllowedErrorcould be copied whennavigator.clipboard.writeText(…)fails, but- a further fallback succeeds.
See https://github.com/lgarron/clipboard-polyfill/issues/167 for more information.
- Fix an issue where the contents of a
- v4.0.22024-01-07 · 2024-01-07 07:39 UTC
查看更新说明
Release notes:
- Convert array iterator
forloops to index iteration.- This avoids conflicts with additional methods defined on the
Arrayprototype. It is generally not good practice to modify global prototypes with new methods (and if you do, you should make sure they are not enumerable: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#enumerable), but this should reduce the chance of conflict when you are usingclipboard-polyfill.
- This avoids conflicts with additional methods defined on the
- Convert array iterator
- v4.0.12023-09-06 · 2023-09-06 22:27 UTC
查看更新说明
Release notes:
- Add checks when accessing expected global objects, in order to throw better error messages.
- v4.0.02023-02-03 · 2023-02-03 07:13 UTC
这个版本没有写更新说明。
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
clipboard-polyfill
⚠️ You don't need clipboard-polyfill to copy text! ⚠️
Note: As of 2020, you can use navigator.clipboard.writeText(...) in the stable versions of all major browsers. This library will only be useful to you if you want to:
- target very old browsers (see below for compatibility) for text copy,
- copy
text/htmlin Firefox ≤126, - use the
ClipboardItemAPI in Firefox ≤126, or - polyfill the API shape in a non-browser environment (e.g. in
jsdom).
See the Compatibility section below for more details.
Summary
Makes copying on the web as easy as:
clipboard.writeText("hello world");
This library is a ponyfill/polyfill for the modern Promise-based asynchronous clipboard API.
Usage
If you use npm, install:
npm install clipboard-polyfill
Sample app that copies text to the clipboard:
import * as clipboard from "clipboard-polyfill";
function handler() {
clipboard.writeText("This text is plain.").then(
() => { console.log("success!"); },
() => { console.log("error!"); }
);
}
window.addEventListener("DOMContentLoaded", function () {
const button = document.body.appendChild(document.createElement("button"));
button.textContent = "Copy";
button.addEventListener("click", handler);
});
Notes:
- You need to call a clipboard operation in response to a user gesture (e.g. the event handler for a
buttonclick).- Some browsers may only allow one clipboard operation per gesture.
async/await syntax
import * as clipboard from "clipboard-polyfill";
async function handler() {
console.log("Previous clipboard text:", await clipboard.readText());
await clipboard.writeText("This text is plain.");
}
window.addEventListener("DOMContentLoaded", function () {
const button = document.body.appendChild(document.createElement("button"));
button.textContent = "Copy";
button.addEventListener("click", handler);
});
More MIME types (data types)
import * as clipboard from "clipboard-polyfill";
async function handler() {
console.log("Previous clipboard contents:", await clipboard.read());
const item = new clipboard.ClipboardItem({
"text/html": new Blob(
["<i>Markup</i> <b>text</b>. Paste me into a rich text editor."],
{ type: "text/html" }
),
"text/plain": new Blob(
["Fallback markup text. Paste me into a rich text editor."],
{ type: "text/plain" }
),
});
await clipboard.write([item]);
}
window.addEventListener("DOMContentLoaded", function () {
const button = document.body.appendChild(document.createElement("button"));
button.textContent = "Copy";
button.addEventListener("click", handler);
});
Check the Clipboard API specification for more details.
Notes:
- You'll need to use
asyncfunctions for theawaitsyntax. - Currently,
text/plainandtext/htmlare the only data types that can be written to the clipboard across most browsers. - If you try to copy unsupported data types, they may be silently dropped (e.g. Safari 13.1) or the call may throw an error (e.g. Chrome 83). In general, it is not possible to tell when data types are dropped.
- In some current browsers,
read()may only return a subset of supported data types, even if the clipboard contains more data types. There is no way to tell if there were more data types.
overwrite-globals version
If you want the library to overwrite the global clipboard API with its implementations, import clipboard-polyfill/overwrite-globals. This will turn the library from a ponyfill into a proper polyfill, so you can write code as if the async clipboard API were already implemented in your browser:
import "clipboard-polyfill/overwrite-globals";
async function handler() {
const item = new window.ClipboardItem({
"text/html": new Blob(
["<i>Markup</i> <b>text</b>. Paste me into a rich text editor."],
{ type: "text/html" }
),
"text/plain": new Blob(
["Fallback markup text. Paste me into a rich text editor."],
{ type: "text/plain" }
),
});
navigator.clipboard.write([item]);
}
window.addEventListener("DOMContentLoaded", function () {
const button = document.body.appendChild(document.createElement("button"));
button.textContent = "Copy";
button.addEventListener("click", handler);
});
This approach is not recommended, because it may break any other code that interacts with the clipboard API globals, and may be incompatible with future browser implementations.
Flat-file version with Promise included
If you need to grab a version that "just works", download clipboard-polyfill.window-var.promise.es5.js and include it using a <script> tag:
<script src="./clipboard-polyfill.window-var.promise.es5.js"></script>
<button onclick="copy()">Copy text!</button>
<script>
// `clipboard` is defined on the global `window` object.
function copy() {
clipboard.writeText("hello world!");
}
</script>
Bundling / tree shaking / minification / CommonJS
Thanks to the conveniences of the modern JS ecosystem, we do not provide tree shaken, minified, or CommonJS builds anymore. To get such builds without losing compatibility, pass clipboard-polyfill builds through esbuild. For example:
mkdir temp && cd temp && npm install clipboard-polyfill esbuild
# Minify the ES6 build:
echo 'export * from "clipboard-polyfill";' | npx esbuild --format=esm --target=es6 --bundle --minify
# Include just the `writeText(…)` export and minify:
echo 'export { writeText } from "clipboard-polyfill";' | npx esbuild --format=esm --target=es6 --bundle --minify
# Minify an ES5 build:
npx esbuild --format=esm --target=es5 --bundle --minify node_modules/clipboard-polyfill/dist/es5/window-var/clipboard-polyfill.window-var.promise.es5.js
# Get a CommonJS build:
echo 'export * from "clipboard-polyfill";' | npx esbuild --format=cjs --target=es6 --bundle
Why clipboard-polyfill?
Browsers have implemented several clipboard APIs over time, and writing to the clipboard without triggering bugs in various old and current browsers is fairly tricky. In every browser that supports copying to the clipboard in some way, clipboard-polyfill attempts to act as close as possible to the async clipboard API. (See above for disclaimers and limitations.)
See this presentation for for a longer history of clipboard access on the web.
Compatibility
- ☑️: Browser has native async clipboard support.
- ✅:
clipboard-polyfilladds support. - ❌: Support is not possible.
- Bold browser names indicate the latest functionality changes for stable versions of modern browsers.
Write support by earliest browser version:
| Browser | writeText() | write() (HTML) | write() (other formats) |
|---|---|---|---|
| Safari 13.1 | ☑️ | ☑️ | ☑️ (image/uri-list, image/png) |
| Chrome 86ᵃ / Edge 86 | ☑️ | ☑️ | ☑️ (image/png) |
| Chrome 76ᵃ / Edge 79 | ☑️ | ✅ | ☑️ (image/png) |
| Chrome 66ᵃ / Firefox 63 | ☑️ | ✅ | ❌ |
| Safari 10 / Chrome 42ᵃ / Edgeᵈ / Firefox 41 | ✅ | ✅ᵇ | ❌ |
| IE 9 | ✅ᶜ | ❌ | ❌ |
Read support:
| Browser | readText() | read() (HTML) | read() (other formats) |
|---|---|---|---|
| Safari 13.1 | ☑️ | ☑️ | ☑️ (image/uri-list, image/png) |
| Chrome 76 ᵃ / Edge 79 | ☑️ | ❌ | ☑️ (image/png) |
| Chrome 66ᵃ | ☑️ | ❌ | ❌ |
| IE 9 | ✅ᶜ | ❌ | ❌ |
| Firefox | ❌ | ❌ | ❌ |
- ᵃ Also includes versions of Edge, Opera, Brave, Vivaldi, etc. based on the corresponding version of Chrome.
- ᵇ HTML did not work properly on mobile Safari in the first few releases of version 10.
- ᶜ In Internet Explorer, you will need to polyfill
window.Promiseif you want the library to work. - ᵈ In older versions of Edge (Spartan):
- It may not be possible to tell if a copy operation succeeded (Edge Bug #14110451, Edge Bug #14080262).
clipboard-polyfillwill always report success in this case. - Only the last data type you specify is copied to the clipboard (Edge Bug #14080506). Consider placing the most important data type last in the object that you pass to the
ClipboardItemconstructor. - The
text/htmldata type is not written using the expectedCF_HTMLformat.clipboard-polyfilldoes not try to work around this, since 1) it would require fragile browser version sniffing, 2) users of Edge are not generally stuck on version < 17, and 3) the failure mode for other browsers would be that invalid clipboard HTML is copied. (Edge Bug #14372529, #73)
- It may not be possible to tell if a copy operation succeeded (Edge Bug #14110451, Edge Bug #14080262).
clipboard-polyfill uses a variety of heuristics to work around compatibility bugs. Please let us know if you are running into compatibility issues with any of the browsers listed above.
History
Browser history
| Browser | First version supportingnavigator.clipboard.writeText(...) | Release Date |
|---|---|---|
| Chrome | 66+ | April 2018 |
| Firefox | 53+ | October 2018 |
| Edge | 79+ (first Chromium-based release) | January 2020 |
| Safari | 13.1+ | March 2020 |
Project history
This project dates from a time when clipboard access in JS was barely becoming possible, and ergonomic clipboard API efforts were stalling. (See this presentation for a bit more context.) Fortunately, an ergonomic API with the same functionality is now available in all modern browsers since 2020:
- 2015: Browsers start supporting the defunct
document.execCommand("copy")call (with many, many issues). - 2015: Started this project as
clipboard.js(half a year before @zenorocha picked the same name 😛). - 2016: Renewed discussions about an async clipboard API (e.g. proposal doc,
crbug.com/593475). - 2017: Renamed this project to
clipboard-polyfillto reflect av2API overhaul aligned with the draft spec. - 2018: Browsers start supporting
navigator.clipboard.writeText(). - 2020: Browsers start supporting
navigator.clipboard.write()(includingtext/htmlsupport).
Thanks to Gary Kacmarcik, Hallvord Steen, and others for helping to bring the async clipboard API to life!
This is way too complicated!
If you only need to copy text in modern browsers, consider using navigator.clipboard.writeText() directly: https://caniuse.com/mdn-api_clipboard_writetext
If you need copy text in older browsers as well, you could also try this gist for a simple hacky solution.