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

@usefy/use-copy-to-clipboard

v0.2.4

Published

A React hook for copying text to clipboard with fallback support

Readme


Overview

@usefy/use-copy-to-clipboard provides a simple way to copy text to the clipboard using the modern Clipboard API with automatic fallback for older browsers. Features include auto-reset timeout, success/error callbacks, and copy state tracking.

Part of the @usefy ecosystem — a collection of production-ready React hooks designed for modern applications.

Why use-copy-to-clipboard?

  • Zero Dependencies — Pure React implementation with no external dependencies
  • TypeScript First — Full type safety with exported interfaces
  • Modern + Fallback — Uses Clipboard API with automatic execCommand fallback
  • Auto Reset — Copied state automatically resets after configurable timeout
  • CallbacksonSuccess and onError callbacks for custom handling
  • Async/Await — Returns promise with boolean success indicator
  • SSR Compatible — Works seamlessly with Next.js, Remix, and other SSR frameworks
  • Stable References — Memoized copy function for optimal performance
  • Well Tested — Comprehensive test coverage with Vitest

Installation

# npm
npm install @usefy/use-copy-to-clipboard

# yarn
yarn add @usefy/use-copy-to-clipboard

# pnpm
pnpm add @usefy/use-copy-to-clipboard

Peer Dependencies

This package requires React 18 or 19:

{
  "peerDependencies": {
    "react": "^18.0.0 || ^19.0.0"
  }
}

Quick Start

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function CopyButton() {
  const [copiedText, copy] = useCopyToClipboard();

  return (
    <button onClick={() => copy("Hello World!")}>
      {copiedText ? "Copied!" : "Copy"}
    </button>
  );
}

API Reference

useCopyToClipboard(options?)

A hook that provides clipboard copy functionality with state tracking.

Parameters

| Parameter | Type | Description | | --------- | --------------------------- | --------------------- | | options | UseCopyToClipboardOptions | Configuration options |

Options

| Option | Type | Default | Description | | ----------- | ------------------------ | ------- | --------------------------------------------------------------------- | | timeout | number | 2000 | Time in ms before copiedText resets to null. Set to 0 to disable. | | onSuccess | (text: string) => void | — | Callback called when copy succeeds | | onError | (error: Error) => void | — | Callback called when copy fails |

Returns [copiedText, copy]

| Index | Type | Description | | ----- | ------------------------------------ | -------------------------------------------- | | [0] | string \| null | The last successfully copied text, or null | | [1] | (text: string) => Promise<boolean> | Async function to copy text |


Examples

Basic Copy Button

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function CopyButton({ text }: { text: string }) {
  const [copiedText, copy] = useCopyToClipboard();

  return (
    <button onClick={() => copy(text)}>
      {copiedText === text ? "Copied!" : "Copy to Clipboard"}
    </button>
  );
}

Copy with Visual Feedback

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function CopyWithIcon({ text }: { text: string }) {
  const [copiedText, copy] = useCopyToClipboard();
  const isCopied = copiedText === text;

  return (
    <button onClick={() => copy(text)} className={isCopied ? "copied" : ""}>
      {isCopied ? (
        <CheckIcon className="icon" />
      ) : (
        <CopyIcon className="icon" />
      )}
      {isCopied ? "Copied!" : "Copy"}
    </button>
  );
}

Code Block with Copy

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function CodeBlock({ code, language }: { code: string; language: string }) {
  const [copiedText, copy] = useCopyToClipboard();

  return (
    <div className="code-block">
      <div className="code-header">
        <span>{language}</span>
        <button onClick={() => copy(code)}>
          {copiedText === code ? "Copied!" : "Copy Code"}
        </button>
      </div>
      <pre>
        <code>{code}</code>
      </pre>
    </div>
  );
}

Custom Timeout

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function LongFeedbackCopy() {
  // Show "Copied!" for 5 seconds
  const [copiedText, copy] = useCopyToClipboard({ timeout: 5000 });

  return (
    <button onClick={() => copy("Long feedback!")}>
      {copiedText ? "Copied!" : "Copy"}
    </button>
  );
}

Persistent Copied State

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function PersistentCopy() {
  // Never auto-reset the copied state
  const [copiedText, copy] = useCopyToClipboard({ timeout: 0 });

  return (
    <div>
      <button onClick={() => copy("Persistent!")}>
        {copiedText ? "Copied!" : "Copy"}
      </button>
      {copiedText && <span>Copied text: {copiedText}</span>}
    </div>
  );
}

With Callbacks

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";
import { toast } from "your-toast-library";

function CopyWithToast({ text }: { text: string }) {
  const [, copy] = useCopyToClipboard({
    onSuccess: (copiedText) => {
      toast.success(`Copied: ${copiedText}`);
    },
    onError: (error) => {
      toast.error(`Failed to copy: ${error.message}`);
    },
  });

  return <button onClick={() => copy(text)}>Copy</button>;
}

Async Handling

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function AsyncCopy({ text }: { text: string }) {
  const [, copy] = useCopyToClipboard();
  const [status, setStatus] = useState<"idle" | "success" | "error">("idle");

  const handleCopy = async () => {
    const success = await copy(text);
    setStatus(success ? "success" : "error");
  };

  return (
    <div>
      <button onClick={handleCopy}>Copy</button>
      {status === "success" && (
        <span className="success">Copied successfully!</span>
      )}
      {status === "error" && <span className="error">Failed to copy</span>}
    </div>
  );
}

Share URL Button

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function ShareButton() {
  const [copiedText, copy] = useCopyToClipboard();

  const handleShare = () => {
    copy(window.location.href);
  };

  return (
    <button onClick={handleShare}>
      {copiedText ? "Link Copied!" : "Share Link"}
    </button>
  );
}

Copy Multiple Items

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function CopyList({ items }: { items: string[] }) {
  const [copiedText, copy] = useCopyToClipboard();

  return (
    <ul>
      {items.map((item) => (
        <li key={item}>
          <span>{item}</span>
          <button onClick={() => copy(item)}>
            {copiedText === item ? "Copied!" : "Copy"}
          </button>
        </li>
      ))}
    </ul>
  );
}

API Key Display

import { useCopyToClipboard } from "@usefy/use-copy-to-clipboard";

function ApiKeyDisplay({ apiKey }: { apiKey: string }) {
  const [copiedText, copy] = useCopyToClipboard();

  const maskedKey = `${apiKey.slice(0, 4)}${"*".repeat(20)}${apiKey.slice(-4)}`;

  return (
    <div className="api-key">
      <code>{maskedKey}</code>
      <button onClick={() => copy(apiKey)}>
        {copiedText === apiKey ? "Copied!" : "Copy Key"}
      </button>
    </div>
  );
}

TypeScript

This hook is written in TypeScript with exported types.

import {
  useCopyToClipboard,
  type UseCopyToClipboardOptions,
  type UseCopyToClipboardReturn,
  type CopyFn,
} from "@usefy/use-copy-to-clipboard";

// Return type
const [copiedText, copy]: UseCopyToClipboardReturn = useCopyToClipboard();

// copiedText: string | null
// copy: (text: string) => Promise<boolean>

// Options type
const options: UseCopyToClipboardOptions = {
  timeout: 3000,
  onSuccess: (text) => console.log("Copied:", text),
  onError: (error) => console.error("Error:", error),
};

Browser Support

This hook uses the modern Clipboard API when available, with automatic fallback to document.execCommand('copy') for older browsers.

| Browser | Clipboard API | Fallback | | -------------- | ------------- | -------- | | Chrome 66+ | Yes | - | | Firefox 63+ | Yes | - | | Safari 13.1+ | Yes | - | | Edge 79+ | Yes | - | | IE 11 | No | Yes | | Older browsers | No | Yes |


Testing

This package maintains comprehensive test coverage to ensure reliability and stability.

Test Coverage

📊 View Detailed Coverage Report (GitHub Pages)

Test Categories

  • Copy text successfully using Clipboard API
  • Update copiedText after successful copy
  • Return true on successful copy
  • Handle empty string
  • Handle special characters
  • Reset copiedText after default timeout (2000ms)
  • Reset after custom timeout
  • Not reset when timeout is 0
  • Reset timer on consecutive copies
  • Use fallback when Clipboard API is not available
  • Try fallback when Clipboard API throws error

License

MIT © mirunamu

This package is part of the usefy monorepo.