Copy text to clipboard with a simple React hook that handles success and error states.
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 };
}
navigator.clipboard.writeText() API.isCopied state to provide user feedback.isCopied state after 2 seconds.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>
);
}
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 };
}
A simple hook that makes clipboard operations seamless and user-friendly.