clipboard-polyfill
A ponyfill for the async Clipboard API, giving reliable copy/paste of text and rich content across old and modern browsers.
Repository Health
Technical Analysis
clipboard-polyfill makes reading from and writing to the system clipboard as simple as calling clipboard.writeText(...) or clipboard.readText(), backed by a Promise-based API that mirrors the W3C asynchronous Clipboard specification. Where a browser already implements navigator.clipboard natively, the library defers to it; where it doesn’t (or where a browser’s implementation has known bugs, such as text/html support in older Firefox), it falls back to a layered set of strategies built on document.execCommand('copy'), temporary DOM selections, and shadow DOM tricks worked out through years of cross-browser experimentation.
Beyond plain text, it implements a ClipboardItem polyfill so callers can write multiple MIME types (e.g. text/html alongside a text/plain fallback) in one call, matching the shape of the native API closely enough that code written against it keeps working as browsers catch up. An overwrite-globals entry point lets consumers who want a true polyfill (rather than a ponyfill) replace navigator.clipboard directly, at the cost of some global-mutation risk the maintainers are upfront about in the docs.
What You Get
- A drop-in
writeText()/readText()pair that mirrors the native async Clipboard API’s Promise-based signature ClipboardItemandwrite()/read()support for copying multiple MIME types (e.g.text/htmlplus atext/plainfallback) in one call- Automatic fallback through
execCommand('copy'), temporary DOM selections, and shadow DOM when a browser has no native clipboard support - An
overwrite-globalsentry point for consumers who want the library to patchnavigator.clipboarddirectly instead of being called as a standalone module - ES5 and ES6 builds, including a flat window-var build with a bundled Promise polyfill for legacy environments (e.g. IE9)
Common Use Cases
- Adding a reliable “Copy to clipboard” button in a web app that still needs to support older browser versions
- Copying both a plain-text fallback and formatted
text/htmlcontent in one operation for pasting into rich-text editors - Polyfilling
navigator.clipboardin a non-browser DOM environment such as jsdom-based tests - Supporting clipboard read/write on legacy Edge/IE deployments where the native async Clipboard API never shipped
Under The Hood
Architecture
The library is organized as a thin public surface (src/clipboard-polyfill/entries/es6/clipboard-polyfill.es6.ts) that re-exports a small set of implementation modules: implementations/text.ts and implementations/blob.ts hold the public writeText/readText/write/read functions, ClipboardItem/ClipboardItemPolyfill.ts implements the ClipboardItem constructor, and strategies/dom.ts and strategies/internet-explorer.ts hold the browser-specific fallback mechanics (temporary DOM selection, shadow DOM, execCommand, and legacy IE clipboard access). Each public function first checks for originalNavigatorClipboardWriteText/ReadText captured in builtins/builtin-globals.ts and only falls through to the DOM-based strategies when the native API is absent or throws, giving a clear layered-fallback data flow rather than a monolithic implementation. A separate overwrite-globals entry point composes the same core functions but assigns them onto window.navigator.clipboard, isolating the riskier global-patching behavior from the default ponyfill import.
Tech Stack
Written in TypeScript targeting es5+dom lib types with strictNullChecks enabled, built and tested with Bun (bun run script/build.ts, bun test) rather than Node, and bundled via esbuild for consumers who want tree-shaken or CommonJS output. Linting and formatting run through Biome (biome.json disables a handful of default rules like noExplicitAny and noDelete to accommodate the low-level DOM/Promise-polyfill code). The project ships both ES6 and ES5 (with an included lightweight Promise polyfill) build targets, and a small demo app under src/demo/ built with the same esbuild pipeline.
Code Quality
Tests are colocated with implementation files as *.test.ts (e.g. text.modern-browser.test.ts, text.execCommand-fallback.test.ts, text.blank-document.test.ts), run via Bun’s test runner, and CI (.github/workflows/) runs make lint, make test-bun, and a mock-test pass that exercises fallback code paths (missing Promise, older browser API shapes) under src/mock-test/. Naming is consistent and the fallback strategies are commented with citations to specific upstream browser bugs (e.g. old Edge CF_HTML issues), which is unusually thorough for a small utility library, though some older files retain var-based ES5-style code left over from the library’s long history rather than being modernized to const/let throughout.
API Design
The public API is deliberately minimal and mirrors the native navigator.clipboard shape (writeText, readText, write, read, ClipboardItem) so that call sites need no polyfill-specific knowledge — code written against the native API mostly works unchanged. Getting started requires a single import and no configuration; the README documents async/await usage, multi-MIME-type writes, and the overwrite-globals alternative import path clearly, along with an explicit compatibility matrix per browser version so consumers know exactly what is and isn’t polyfilled.