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

uniclip

v0.0.1

Published

The universal clipboard library for browser, Node, Bun, Deno, Electron, Tauri, and React Native.

Downloads

34

Readme

uniclip

version downloads

The universal clipboard library for the browser, Node, Bun, Deno, Electron, Tauri, and React Native

How? import { clipboard } from "uniclip" once and the same code reads, writes, and watches the OS clipboard everywhere. The package.json exports map picks the right backend for each runtime, so there's no if (typeof navigator …) branching.

It replaces a stack of single-purpose libraries (clipboardy, clipboard.js, copy-to-clipboard, arboard) with one tiny package and a typed multi-format API.

Install

npm install uniclip

Usage

import { clipboard } from "uniclip";

await clipboard.writeText("hi");
const text = await clipboard.readText();

The same import works in every supported runtime. Writing multiple formats at once is just as easy:

await clipboard.write({
  "text/plain": "hi",
  "text/html": "<b>hi</b>",
  "application/x-react-grab": JSON.stringify(payload),
});

All formats land on the OS clipboard in a single transaction.

Per-runtime examples

If you're using a specific runtime, the snippets below are the practical starting points.

Browser

import { clipboard } from "uniclip";

await clipboard.writeText("hello");
const text = await clipboard.readText();

For multi-format writes from a keyboard shortcut, use writeSync so the user-gesture token survives:

document.addEventListener("keydown", (event) => {
  if ((event.metaKey || event.ctrlKey) && event.key === "c") {
    clipboard.writeSync({
      "text/plain": "fallback for terminals",
      "text/html": "<b>fallback for editors</b>",
    });
  }
});

Node / Bun / Deno

import { clipboard } from "uniclip";

await clipboard.writeText("from the cli");
const text = await clipboard.readText();

You'll need one of the platform helpers installed:

  • macOS ships osascript by default.
  • Windows ships powershell.exe by default.
  • Linux needs xclip (X11) or wl-copy / wl-paste (Wayland).

If a helper is missing, uniclip throws a MissingDependencyError with a .hint telling you exactly what to install.

Electron

uniclip's exports map auto-routes to the Electron build, which uses clipboard from the Electron API in the main process and falls back to the browser path in the renderer.

import { clipboard } from "uniclip";

await clipboard.write({ "text/plain": "hi", "text/html": "<b>hi</b>" });

If you proxy the clipboard through ipcRenderer, see Custom backends below.

Tauri v2

Add the official plugin to your Tauri app:

npm install @tauri-apps/plugin-clipboard-manager

Then use uniclip the same way. The Tauri build delegates to the plugin under the hood.

import { clipboard } from "uniclip";

await clipboard.writeText("hi from tauri");

React Native

Add one of the supported clipboard modules:

npm install @react-native-clipboard/clipboard
# or
npm install expo-clipboard

Then:

import { clipboard } from "uniclip";

await clipboard.writeText("hi from rn");

writeImage works when the loaded module exposes setImage(base64). writeFiles and writeRTF are not available on RN.

Watching the clipboard

import { clipboard } from "uniclip";

const off = clipboard.watch((snapshot) => {
  console.log("clipboard changed:", snapshot.text);
});

// later:
off();

watch polls every 500 ms by default and dedupes identical states. On iOS and Android (RN), it uses native event subscriptions when the underlying module exposes them. Errors go to options.onError (default console.error); transient errors keep the loop alive, non-recoverable errors halt it.

const off = clipboard.watch((snapshot) => console.log(snapshot.text), {
  intervalMs: 250,
  signal: abortController.signal,
  onError: (error) => console.warn("[uniclip]", error),
});

Drag and drop

dataTransfer is a sibling export for the drag-and-drop side of the same MIME-keyed transfer model. Browser and Electron renderer only.

import { dataTransfer } from "uniclip";

draggable.addEventListener("dragstart", (event) => {
  dataTransfer.set(event, {
    "text/plain": "drag me",
    "text/html": "<em>drag me</em>",
  });
});

const cleanup = dataTransfer.dropZone(document.querySelector("#zone"), (snap) => {
  console.log("dropped:", snap.text, snap.files.length);
});
// later:
cleanup();

Has-checks (no privacy banner)

iOS 14+, macOS 15.4+, and Android 12+ pop a paste banner when you actually read the clipboard. Use the has* family to ask "is there content of kind X?" without triggering the banner:

if (await clipboard.hasURL()) {
  const url = await clipboard.readURL();
}

Available: clipboard.types, has, hasText, hasHTML, hasRTF, hasImage, hasFiles, hasURL.

Custom backends

Override the active backend for Tauri apps with custom Rust IPC clipboards, Electron renderers proxying through the main process, or test fixtures that mock the clipboard layer entirely.

import { setClipboardImplementation } from "uniclip";

setClipboardImplementation({
  read: async () => stubSnapshot,
  write: async (record) => mockServer.write(record),
  watch: (callback) => mockServer.subscribe(callback),
});

// reset to default:
setClipboardImplementation(null);

Errors

import {
  ClipboardError,
  ClipboardReadError,
  ClipboardWriteError,
  MissingDependencyError,
  PermissionDeniedError,
  UnsupportedFormatError,
  UnsupportedRuntimeError,
} from "uniclip";

Every error carries .hint (an actionable installation, permission, or configuration tip), .cause (the underlying platform error), and .recoverable (used by clipboard.watch to decide whether to halt the loop).

API at a glance

clipboard.writeText(text, options?);
clipboard.writeHTML(html, options?);
clipboard.writeRTF(rtf, options?);
clipboard.writeImage(data, options?);
clipboard.writeFiles(paths, options?);
clipboard.writeURL(url, options?);
clipboard.write(record, options?);            // multi-format atomic write
clipboard.writeSync(record, options?);        // browser-only synchronous write

clipboard.readText(options?);
clipboard.readHTML(options?);
clipboard.readRTF(options?);
clipboard.readImage(options?);
clipboard.readFiles(options?);
clipboard.readURL(options?);
clipboard.read(options?);                     // returns a ClipboardSnapshot
clipboard.read(mimeType, options?);           // returns a single value

clipboard.types(options?);
clipboard.has(mime, options?);
clipboard.hasText | hasHTML | hasRTF | hasImage | hasFiles | hasURL(options?);
clipboard.clear(options?);
clipboard.watch(callback, options?);

dataTransfer.set(event, record, options?);
dataTransfer.from(event);
dataTransfer.dropZone(element, callback);

setClipboardImplementation(impl | null);

See packages/uniclip/src/types.ts for the full ClipboardSnapshot, ClipboardWriteRecord, WriteOptions, ReadOptions, WatchOptions, and error class definitions.

Resources & Contributing Back

Looking to contribute back? Check out the Contributing Guide.

Find a bug? Head over to our issue tracker and we'll do our best to help. We love pull requests, too!

→ Start contributing on GitHub

License

uniclip is MIT-licensed open-source software.