shadimage
ratneshc
hookuse-copy-to-clipboardsource: ok · refreshed

useCopyToClipboard

npx shadcn add "https://ratneshc.com/r/use-copy-to-clipboard.json"
free

Where it goes

kanban

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Files1 · source cached 10/8/2026, 10:09:49 AM

src/registry/hooks/use-copy-to-clipboard/use-copy-to-clipboard.ts
// Thanks @ncdai

"use client";

import * as React from "react";

export type CopyState = "idle" | "done" | "error";

export type UseCopyToClipboardOptions = {
  /** Called when the text is successfully copied. */
  onCopySuccess?: (text: string) => void;
  /** Called when the copy operation fails. */
  onCopyError?: (error: Error) => void;
  /** The delay in milliseconds before resetting the state to "idle". Defaults to 1500. */
  resetDelay?: number;
};

export function useCopyToClipboard({
  onCopySuccess,
  onCopyError,
  resetDelay = 1500,
}: UseCopyToClipboardOptions = {}) {
  const [state, setState] = React.useState<CopyState>("idle");
  const resetTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(
    null
  );

  const copy = React.useCallback(
    async (text: string | (() => string)) => {
      // Clear any pending reset
      if (resetTimeoutRef.current) {
        clearTimeout(resetTimeoutRef.current);
      }

      try {
        const finalText = typeof text === "function" ? text() : text;
        await navigator.clipboard.writeText(finalText);

        setState("done");

        onCopySuccess?.(finalText);
      } catch (error) {
        setState("error");

        onCopyError?.(
          error instanceof Error ? error : new Error("Copy failed")
        );
      } finally {
        // Schedule reset to idle
        resetTimeoutRef.current = setTimeout(() => {
          setState("idle");
        }, resetDelay);
      }
    },
    [onCopySuccess, onCopyError, resetDelay]
  );

  return { state, copy } as const;
}

More from ratneshc

Browse all components in this library →