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;
}