useClipboard
Copy text to clipboard with success feedback and error handling in React applications.
useClipboard
Copy text to clipboard with success feedback and error handling in React applications.
Quick Copy
Copy your text with a single click.
Installation
npx open-hook add useClipboardyarn dlx open-hook add useClipboardpnpm dlx open-hook add useClipboardAPI Reference
Parameters
| Prop | Type | Default |
|---|---|---|
resetTime? | number | 2000 |
Returns
| Prop | Type | Default |
|---|---|---|
clearCopied? | () => void | - |
copyToClipboard? | (text: string) => Promise<boolean> | - |
isCopied? | boolean | - |
TypeScript Signature
interface UseClipboardReturn {
isCopied: boolean;
copyToClipboard: (text: string) => Promise<boolean>;
clearCopied: () => void;
}
function useClipboard(resetTime?: number): UseClipboardReturn;Advanced Usage Examples
function CodeBlock({ code, language }: { code: string; language: string }) {
const { isCopied, copyToClipboard } = useClipboard(3000);
const handleCopy = async () => {
const success = await copyToClipboard(code);
if (success) {
// Optional: analytics tracking
trackEvent("code_copied", { language });
}
};
return (
<div className="relative">
<pre className="code-block">
<code className={`language-${language}`}>{code}</code>
</pre>
<button
onClick={handleCopy}
className="absolute top-2 right-2 copy-button"
aria-label={isCopied ? "Copied!" : "Copy code"}
>
{isCopied ? (
<>
<CheckIcon /> Copied!
</>
) : (
<>
<CopyIcon /> Copy
</>
)}
</button>
</div>
);
}function FormSummary({ formData }: { formData: any }) {
const { isCopied, copyToClipboard } = useClipboard();
const formatFormData = (data: any) => {
return Object.entries(data)
.map(([key, value]) => `${key}: ${value}`)
.join("\n");
};
const copyAsText = () => {
const formatted = formatFormData(formData);
copyToClipboard(formatted);
};
const copyAsJSON = () => {
const json = JSON.stringify(formData, null, 2);
copyToClipboard(json);
};
const copyAsCsv = () => {
const headers = Object.keys(formData).join(",");
const values = Object.values(formData).join(",");
const csv = `${headers}\n${values}`;
copyToClipboard(csv);
};
return (
<div className="form-summary">
<h3>Form Summary</h3>
<pre>{JSON.stringify(formData, null, 2)}</pre>
<div className="copy-buttons">
<button onClick={copyAsText}>
{isCopied ? "Copied!" : "Copy as Text"}
</button>
<button onClick={copyAsJSON}>Copy as JSON</button>
<button onClick={copyAsCsv}>Copy as CSV</button>
</div>
</div>
);
}function MultiCopyManager() {
const clipboard1 = useClipboard(1500);
const clipboard2 = useClipboard(3000);
const items = [
{ id: 1, label: "API Key", value: "sk-1234567890abcdef" },
{ id: 2, label: "Secret", value: "secret_abcdef1234567890" },
{ id: 3, label: "URL", value: "https://api.example.com/v1" },
];
const copyItem = (value: string, type: "sensitive" | "normal") => {
if (type === "sensitive") {
// Shorter feedback time for sensitive data
clipboard1.copyToClipboard(value);
} else {
clipboard2.copyToClipboard(value);
}
};
return (
<div className="multi-copy">
{items.map((item) => (
<div key={item.id} className="copy-item">
<label>{item.label}:</label>
<code className="value">
{item.label.includes("Secret") ? "••••••••" : item.value}
</code>
<button
onClick={() =>
copyItem(
item.value,
item.label.includes("Secret") ? "sensitive" : "normal"
)
}
>
{clipboard1.isCopied || clipboard2.isCopied ? "Copied!" : "Copy"}
</button>
</div>
))}
</div>
);
}Best Practices
Provide clear feedback and handle errors gracefully:
const { isCopied, copyToClipboard } = useClipboard();
const handleCopy = async () => {
const success = await copyToClipboard(text);
if (success) {
// Show success feedback
showNotification("Copied to clipboard!");
} else {
// Handle failure gracefully
showNotification("Failed to copy. Please try again.", "error");
}
};Security & UX Guidelines
- 🔒 Sensitive Data: Use shorter reset times for sensitive content
- 📱 Mobile Support: Include fallbacks for older browsers
- ♿ Accessibility: Provide proper ARIA labels and announcements
- 🎨 Visual Feedback: Clear success/failure states
Do's and Don'ts
- ✅ Provide visual feedback when copying
- ✅ Use appropriate reset times for different content types
- ✅ Handle clipboard permission errors gracefully
- ✅ Include keyboard shortcuts for power users
- ❌ Don't copy sensitive data without user consent
- ❌ Avoid copying very large amounts of text
- ❌ Don't rely solely on clipboard for critical functionality
- ❌ Avoid copying without clear user intent
Performance Metrics
| Metric | Value | Description |
|---|---|---|
| Bundle Size | ~0.8kb | Minified + gzipped |
| Copy Speed | < 10ms | Modern browsers |
| Fallback Support | IE 11+ | execCommand fallback |
| Memory Usage | Minimal | Single state + timeout |
Browser Compatibility
| Browser | Supported | Notes |
|---|---|---|
| Chrome 66+ | ✅Yes | Full Clipboard API support |
| Firefox 63+ | ✅Yes | Full Clipboard API support |
| Safari 13.1+ | ✅Yes | Full Clipboard API support |
| Edge 79+ | ✅Yes | Full Clipboard API support |
| IE 11 | ✅Yes | execCommand fallback |
| Mobile Safari | ✅Yes | iOS 13.4+ required |
Use Cases
Code Snippets
Copy code blocks and documentation examples with one click.
Share Functionality
Copy URLs, text content, or formatted data for sharing.
Form Data Export
Copy form contents in various formats (JSON, CSV, plain text).
API Keys & Tokens
Securely copy sensitive credentials with clear feedback.
Accessibility
Accessibility Considerations
- Use proper ARIA labels for copy buttons - Announce successful copies to screen readers - Provide keyboard shortcuts (Ctrl+C alternatives) - Include visual and auditory feedback for copy actions - Ensure copy buttons have sufficient contrast and touch targets
Troubleshooting
Internals
How It Works
The hook uses the modern Clipboard API when available, with a fallback to the older document.execCommand('copy') method for broader browser support. It manages the copied state with automatic reset after a specified time and provides both the current state and control functions.
The implementation prioritizes user experience with clear feedback and graceful error handling.
Testing Example
import { renderHook, act } from "@testing-library/react";
import { useClipboard } from "./useClipboard";
// Mock clipboard API
Object.assign(navigator, {
clipboard: {
writeText: jest.fn().mockResolvedValue(undefined),
},
});
// Mock timers
jest.useFakeTimers();
describe("useClipboard", () => {
beforeEach(() => {
jest.clearAllMocks();
});
it("should copy text to clipboard", async () => {
const { result } = renderHook(() => useClipboard());
await act(async () => {
const success = await result.current.copyToClipboard("test text");
expect(success).toBe(true);
});
expect(navigator.clipboard.writeText).toHaveBeenCalledWith("test text");
expect(result.current.isCopied).toBe(true);
});
it("should reset copied state after timeout", async () => {
const { result } = renderHook(() => useClipboard(1000));
await act(async () => {
await result.current.copyToClipboard("test");
});
expect(result.current.isCopied).toBe(true);
act(() => {
jest.advanceTimersByTime(1000);
});
expect(result.current.isCopied).toBe(false);
});
it("should handle clipboard errors", async () => {
const writeTextMock = jest
.fn()
.mockRejectedValue(new Error("Permission denied"));
Object.assign(navigator, {
clipboard: { writeText: writeTextMock },
});
const { result } = renderHook(() => useClipboard());
await act(async () => {
const success = await result.current.copyToClipboard("test");
expect(success).toBe(false);
});
expect(result.current.isCopied).toBe(false);
});
it("should clear copied state manually", async () => {
const { result } = renderHook(() => useClipboard());
await act(async () => {
await result.current.copyToClipboard("test");
});
expect(result.current.isCopied).toBe(true);
act(() => {
result.current.clearCopied();
});
expect(result.current.isCopied).toBe(false);
});
});FAQ
Related Hooks
- useTimeout - Control clipboard feedback timing
- useLocalStorage - Store copied content history
- useClickOutside - Close copy menus on outside clicks
Changelog
- 2.0.0 — Enhanced TypeScript support, improved fallback handling, better error management, comprehensive documentation
- 1.2.0 — Added clearCopied function and customizable reset time
- 1.1.0 — Improved browser compatibility with execCommand fallback
- 1.0.0 — Initial release with basic clipboard functionality