npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

copy-to-clipboard

v4.0.0

Published

Copy stuff into clipboard using JS with fallbacks

Downloads

41,409,386

Readme

Copy to clipboard CI

Simple module exposing an async copy function that uses the Async Clipboard API (navigator.clipboard) in secure contexts (HTTPS / localhost), with automatic fallback to document.execCommand('copy') for non-secure contexts or older browsers.

If you are building using Electron, use their API.

Example

import copy from 'copy-to-clipboard';

await copy('Text');

// Copy with options
await copy('Text', {
  debug: true,
  message: 'Press #{key} to copy',
});

// Copy as HTML (text/html + text/plain written simultaneously)
await copy('<b>Hello <i>world</i></b>', { format: 'text/html' });

// Custom plain-text fallback via onCopy
await copy('<b>Hello <i>world</i></b>', {
  format: 'text/html',
  onCopy: () => new ClipboardItem({
    'text/html': new Blob(['<b>Hello <i>world</i></b>'], { type: 'text/html' }),
    'text/plain': new Blob(['Hello world'], { type: 'text/plain' }),
  }),
});

API

copy(text: string, options?: object): Promise<boolean> — copies text to clipboard. Returns true on success, false if all paths failed (no additional keystrokes were required from the user).

v4 breaking change: copy() is now async and returns Promise<boolean>. Use await copy(...) to get the result.

Options

| Value | Default | Notes | |-------|---------|-------| | options.debug | false | Boolean. Enable output to console. | | options.message | 'Copy to clipboard: #{key}, Enter' | String. Prompt message used when fallbackToPrompt is enabled. All occurrences of #{key} are replaced with ⌘+C on macOS or Ctrl+C otherwise. | | options.format | — | String. MIME type to copy as. Use 'text/html' to copy rich text; 'text/plain' to strip inherited styles when pasting into rich-text editors. When set alongside 'text/html', both text/html and text/plain are written simultaneously via ClipboardItem. | | options.onCopy | — | (clipboardData: ClipboardItem \| DataTransfer) => ClipboardItem \| void. Called before the write. On the async path, receives the constructed ClipboardItem and may return a new one to replace it (useful for custom MIME types or a different plain-text fallback). On the execCommand fallback path, receives the DataTransfer object; return value is ignored. | | options.fallbackToPrompt | false | Boolean. If true, shows a window.prompt() as a last resort when both navigator.clipboard and execCommand fail. Off by default in v4. |

Copy path selection

  1. navigator.clipboard.writeText(text) — used when the page is a secure context (HTTPS / localhost), navigator.clipboard is available, and neither options.format nor options.onCopy is set.
  2. navigator.clipboard.write([ClipboardItem]) — used in a secure context when options.format or options.onCopy is set. Builds a ClipboardItem with text/plain always present; adds the requested MIME type alongside it. onCopy may return a replacement ClipboardItem.
  3. execCommand('copy') fallback — used on non-HTTPS pages, when navigator.clipboard is unavailable, or when the async write throws. Uses a hidden <span> element. preventDefault is only called when options.format is set.
  4. window.prompt() fallback — opt-in via options.fallbackToPrompt: true.

Recipes

HTML copy with stripped plain-text fallback

By default, copy(html, { format: 'text/html' }) puts the raw HTML string in the text/plain slot of the ClipboardItem. If you want apps that only accept plain text to receive readable content instead of markup, use onCopy to supply a stripped version:

function stripHtml(html) {
  const div = document.createElement('div');
  div.innerHTML = html;
  return div.textContent || div.innerText || '';
}

const html = '<b>Hello <i>world</i></b>';

await copy(html, {
  format: 'text/html',
  onCopy: () => new ClipboardItem({
    'text/html': new Blob([html], { type: 'text/html' }),
    'text/plain': new Blob([stripHtml(html)], { type: 'text/plain' }),
  }),
});
// text/html  → '<b>Hello <i>world</i></b>'
// text/plain → 'Hello world'

Custom MIME type

await copy('col1,col2\nval1,val2', {
  format: 'text/csv',
});
// text/csv   → 'col1,col2\nval1,val2'
// text/plain → 'col1,col2\nval1,val2'  (always included as fallback)

Browser support

| Browser | Minimum | Notes | |---------|---------|-------| | Chrome | 76+ | Full ClipboardItem + write() support | | Firefox | 127+ | Full ClipboardItem + write() landed in Firefox 127 (mid-2024) | | Safari | 13.1+ | writeText() and write() available | | Edge | 79+ | Chromium-based; same as Chrome |

execCommand fallback retains support for non-HTTPS contexts and any browser that reaches the catch path.

Note: The async clipboard write must occur within a user gesture (click, keydown, etc.). This library is designed to be called from event handlers, so this constraint is normally satisfied automatically.

Installation

npm i copy-to-clipboard

Available as CommonJS, ES module, and IIFE (for <script> tags):

// ESM
import copy from 'copy-to-clipboard';

// CommonJS
const copy = require('copy-to-clipboard');
<!-- IIFE via CDN — exposes window.copyToClipboard -->
<script src="https://unpkg.com/copy-to-clipboard/dist/index.global.js"></script>

TypeScript

Built-in declarations are included for both CommonJS and ESM consumers.

import copy from 'copy-to-clipboard';
import type { Options } from 'copy-to-clipboard';

const result: boolean = await copy('text');

UI components based on this package

See also

Running Tests

End-to-end tests are powered by Nightwatch using native browser drivers.

npm i
npm test               # Chrome (default)
npm run test:firefox
npm run test:safari
npm run test:edge
npm run test:all       # all local browsers

Safari prerequisite: enable "Allow Remote Automation" in Safari's Develop menu. See Testing with WebDriver in Safari.

CI

Chrome, Firefox, and Edge tests run automatically on every push to master and on pull requests via GitHub Actions (Ubuntu runner, headless).

Cross-browser tests (Chrome, Firefox, Safari, Edge) run on LambdaTest automatically on every version tag (v*) and can be triggered manually from the Actions tab. Requires LT_USERNAME and LT_ACCESS_KEY repository secrets.

npm run test:lt:chrome
npm run test:lt:firefox
npm run test:lt:safari
npm run test:lt:edge
npm run test:lt:all

Breaking changes in v4

  1. copy() is now async — returns Promise<boolean> instead of boolean. Wrap call sites with await.
  2. IE11 support droppedwindow.clipboardData path removed.
  3. window.prompt() fallback is opt-in — set options.fallbackToPrompt: true to enable.
  4. Build output moved to dist/ — direct require('copy-to-clipboard/index.js') paths will break; use the package name only.