The useCopier hook provides robust clipboard copy functionality with success state management, error handling, and customizable callbacks. It's designed for code blocks, buttons, and interactive elements that need copy-to-clipboard functionality.
Note
When using
CodeHighlighter, theuseCodeanduseDemohooks already provide built-in copy functionality, souseCopieris not needed.
A simple example showing how to copy text from an input field.
'use client';
import * as React from 'react';
import { useCopier } from '@mui/internal-docs-infra/useCopier';
import styles from './TextInputCopy.module.css';
export function TextInputCopy() {
const [text, setText] = React.useState('Hello, copy me!');
const { copy, recentlySuccessful } = useCopier(() => text);
return (
<div className={styles.container}>
<input
type="text"
value={text}
onChange={(event) => setText(event.target.value)}
className={styles.input}
placeholder="Enter text to copy..."
/>
<button type="button" onClick={copy} className={styles.button}>
{recentlySuccessful ? '✓ Copied!' : 'Copy'}
</button>
</div>
);
}
import { useCopier } from '@mui/internal-docs-infra/useCopier';
function CodeBlockCopy({ getCode }: { getCode: () => string }) {
const { copy, recentlySuccessful } = useCopier(getCode);
return (
<button onClick={copy} disabled={recentlySuccessful}>
{recentlySuccessful ? '✓ Copied' : 'Copy Code'}
</button>
);
}
import { useCopier } from '@mui/internal-docs-infra/useCopier';
function CopyWithFeedback({ content }: { content: string }) {
const [error, setError] = React.useState<string | null>(null);
const { copy, recentlySuccessful } = useCopier(content, {
onCopied: () => setError(null),
onError: (err) => setError('Failed to copy to clipboard'),
timeout: 3000,
});
return (
<div>
<button onClick={copy}>{recentlySuccessful ? 'Copied!' : 'Copy'}</button>
{error && <span style={{ color: 'red' }}>{error}</span>}
</div>
);
}
import { useCopier } from '@mui/internal-docs-infra/useCopier';
function AnalyticsCopyButton({ text, label }: { text: string; label: string }) {
const { copy, recentlySuccessful } = useCopier(text, {
onCopied: () => {
// Track successful copy events
analytics.track('Code Copied', { label });
},
onError: (error) => {
// Track copy failures
analytics.track('Copy Failed', { label, error: String(error) });
},
onClick: (event) => {
// Track all copy attempts
analytics.track('Copy Attempted', { label });
},
});
return (
<button onClick={copy} className={recentlySuccessful ? 'success' : ''}>
{recentlySuccessful ? 'Copied!' : `Copy ${label}`}
</button>
);
}
const { copy, recentlySuccessful } = useCopier(contents, options);
| Parameter | Type | Description |
|---|---|---|
contents | string | (() => string | undefined) | Static text or function returning text to copy |
options | UseCopierOpts | Optional configuration object |
| Option | Type | Default | Description |
|---|---|---|---|
onCopied | () => void | - | Callback fired after successful copy |
onError | (error: unknown) => void | - | Callback fired when copy fails |
onClick | (event: React.MouseEvent<HTMLButtonElement>) => void | - | Additional click handler |
timeout | number | 2000 | Duration (ms) to show success state |
| Property | Type | Description |
|---|---|---|
copy | (event: React.MouseEvent<HTMLButtonElement>) => void | Function to trigger copy operation |
recentlySuccessful | boolean | Whether copy was recently successful |
export type UseCopierOpts = {
onCopied?: () => void;
onError?: (error: unknown) => void;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
timeout?: number;
};
export function useCopier(
contents: (() => string | undefined) | string,
opts?: UseCopierOpts,
): {
copy: (event: React.MouseEvent<HTMLButtonElement>) => void;
recentlySuccessful: boolean;
};
copy is called, resolves content from string or functionclipboard-copy library for cross-browser compatibilityrecentlySuccessful to true after successful copyThe hook manages internal state for copy feedback:
recentlySuccessful is falsefalse and clears any existing timeouttrue and starts timeout countdownfalsefalse but error callback is firedCopy operations can fail for various reasons:
The hook provides the onError callback to handle these cases gracefully.
Uses the clipboard-copy library which provides:
navigator.clipboard.writeText() API when availabledocument.execCommand('copy') for older browsersCodeHighlighter - Often used together for code copy functionality