avatar

Le Do Nghiem

Software Engineer

  • About me
  • Books
  • Snippets
  • Blog

© 2026 Le Do Nghiem. All rights reserved.

Contact |

Back to Snippets

useCopyToClipboard Hook

Copy text to clipboard with a simple React hook that handles success and error states.

LanguageTypeScript
Last UpdatedDec 21, 2025
use-copy-to-clipboard.ts
import { useState, useCallback } from 'react';

interface UseCopyToClipboardReturn {
  copy: (text: string) => Promise<void>;
  isCopied: boolean;
  error: Error | null;
}

export function useCopyToClipboard(): UseCopyToClipboardReturn {
  const [isCopied, setIsCopied] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  const copy = useCallback(async (text: string) => {
    try {
      await navigator.clipboard.writeText(text);
      setIsCopied(true);
      setError(null);
      
      // Reset after 2 seconds
      setTimeout(() => setIsCopied(false), 2000);
    } catch (err) {
      setError(err instanceof Error ? err : new Error('Failed to copy'));
      setIsCopied(false);
    }
  }, []);

  return { copy, isCopied, error };
}

Copying text to the clipboard is a common feature in modern web applications — for sharing links, copying codes, or duplicating content. This hook provides a clean way to handle clipboard operations with feedback.

import { useState, useCallback } from 'react';

interface UseCopyToClipboardReturn {
  copy: (text: string) => Promise<void>;
  isCopied: boolean;
  error: Error | null;
}

export function useCopyToClipboard(): UseCopyToClipboardReturn {
  const [isCopied, setIsCopied] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  const copy = useCallback(async (text: string) => {
    try {
      await navigator.clipboard.writeText(text);
      setIsCopied(true);
      setError(null);
      
      // Reset after 2 seconds
      setTimeout(() => setIsCopied(false), 2000);
    } catch (err) {
      setError(err instanceof Error ? err : new Error('Failed to copy'));
      setIsCopied(false);
    }
  }, []);

  return { copy, isCopied, error };
}

How It Works

  • Uses the modern navigator.clipboard.writeText() API.
  • Manages isCopied state to provide user feedback.
  • Handles errors gracefully.
  • Automatically resets the isCopied state after 2 seconds.

Example Usage

function CopyButton({ text }: { text: string }) {
  const { copy, isCopied, error } = useCopyToClipboard();

  return (
    <div>
      <button onClick={() => copy(text)}>
        {isCopied ? 'Copied!' : 'Copy to Clipboard'}
      </button>
      {error && <p className="error">Failed to copy</p>}
    </div>
  );
}

With Fallback for Older Browsers

export function useCopyToClipboardWithFallback(): UseCopyToClipboardReturn {
  const [isCopied, setIsCopied] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  const copy = useCallback(async (text: string) => {
    try {
      // Try modern API first
      if (navigator.clipboard && window.isSecureContext) {
        await navigator.clipboard.writeText(text);
      } else {
        // Fallback for older browsers
        const textArea = document.createElement('textarea');
        textArea.value = text;
        textArea.style.position = 'fixed';
        textArea.style.left = '-999999px';
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();
        document.execCommand('copy');
        textArea.remove();
      }
      
      setIsCopied(true);
      setError(null);
      setTimeout(() => setIsCopied(false), 2000);
    } catch (err) {
      setError(err instanceof Error ? err : new Error('Failed to copy'));
      setIsCopied(false);
    }
  }, []);

  return { copy, isCopied, error };
}

Use Cases

  • Copy shareable links
  • Copy code snippets
  • Copy user IDs or tokens
  • Copy formatted text
  • Copy API keys or credentials

Notes

  • The modern API requires a secure context (HTTPS or localhost).
  • The fallback method works in older browsers but is deprecated.
  • Always provide visual feedback when copying succeeds.
  • Consider showing a toast notification for better UX.

A simple hook that makes clipboard operations seamless and user-friendly.

Previous Snippet

useIntersectionObserver

Next Snippet

Sleep Function