For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. An agent skill is available at /.well-known/agent-skills/site-skill.md.
1
Sponsor

useClipboard

Copy text with success feedback, errors, and a reset timer.

Copying is an asynchronous action, not an immediate guarantee. A browser can reject a clipboard write, and a button that always says “Copied” can report success even when nothing was copied.

useClipboard combines the write with its feedback state: copy performs the request, copied becomes true after success, and error explains a failure. A reset timer returns the control to its normal label so it is ready for the next copy.

Feedback belongs to the result

Use it for a copyable input, an install command, or a code block. Start the write from a user action and display success only from the returned state. This hook writes text; it does not read the clipboard or handle image copying.

Repeated copies restart the success interval. A late result from an older request cannot overwrite a newer request's feedback. Browser security requirements still apply, so failure should remain visible rather than being silently treated as success.

Edit the text below, copy it, and watch the feedback reset. The Docs' code-copy controls share this implementation through the existing compatibility hook.

Preview

Edit the text, then copy it.

Installation

The starter includes hooks/use-clipboard.ts. Import the hook directly; no application-wide provider is required.

Usage

import { useClipboard } from "@/hooks/use-clipboard";
 
const { copy, copied, error } = useClipboard({ timeout: 2000 });
<Button onClick={() => void copy("Hello")}>
  {copied ? "Copied" : "Copy"}
</Button>;

API Reference

APITypeBehavior / default
timeoutnumber2000ms; 0 keeps the success state
copy(text)Promise<boolean>true after the browser accepts the write
copiedbooleanCurrent success state
errorError or nullLast copy failure

Behavior

The editable input above is an InputCopy-style example. The Code tabs and the Docs' existing CopyButton use the same implementation through useCopyToClipboard. Clipboard writes require a secure context such as HTTPS or localhost and browser permission. A newer request supersedes stale async results. Timers are reset on repeated copies and cleared on unmount.

Implementation

"use client";
import { useCallback, useEffect, useRef, useState } from "react";

export const useClipboard = ({ timeout = 2000 }: { timeout?: number } = {}) => {
  const [copied, setCopied] = useState(false);
  const [copyError, setError] = useState<Error | null>(null);
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const request = useRef(0);
  useEffect(
    () => () => {
      request.current += 1;
      if (timer.current) {
        clearTimeout(timer.current);
      }
    },
    []
  );
  const copy = useCallback(
    async (text: string) => {
      request.current += 1;
      const id = request.current;
      if (timer.current) {
        clearTimeout(timer.current);
      }
      setCopied(false);
      setError(null);
      try {
        await navigator.clipboard.writeText(text);
        if (id !== request.current) {
          return false;
        }
        setCopied(true);
        if (timeout > 0) {
          timer.current = setTimeout(() => setCopied(false), timeout);
        }
        return true;
      } catch (error) {
        if (id === request.current) {
          setError(
            error instanceof Error
              ? error
              : new Error("Unable to copy to the clipboard.")
          );
        }
        return false;
      }
    },
    [timeout]
  );
  return { copied, copy, error: copyError };
};