Hooks
useCopyToClipboard
BetaSince 0.1.0
Copies text to the clipboard and says whether it worked, for a copy control of your own.
import { useCopyToClipboard } from "@anantya/uix";Overview
useCopyToClipboard copies text to the clipboard and tells you whether it worked. Copy Button uses it. In product code, use it only for a copy action with a text label, such as Copy payment link, which Copy Button doesn't have.
Building block
To copy a value, use Copy Button, which also shows a check and announces the result.
Missing a component? Ask for it instead of building your own.
Signature
function useCopyToClipboard(options?: UseCopyToClipboardOptions): UseCopyToClipboardReturn;
interface UseCopyToClipboardOptions {
timeout?: number;
}
interface UseCopyToClipboardReturn {
copy: (text: string) => Promise<boolean>;
copied: boolean;
error: Error | undefined;
}Parameters
| Option | Type | Default | Description |
|---|---|---|---|
timeout | number | 2000 | How long copied stays true after a copy, in milliseconds. |
Returns
| Name | Type | Description |
|---|---|---|
copy | (text: string) => Promise<boolean> | Copies text. Resolves to whether it was copied, and never rejects. Keeps its identity across renders. |
copied | boolean | True from a copy until timeout has passed or a later copy fails. Each copy starts the timeout again. |
error | Error | undefined | Why the last copy failed, such as a denied permission, until a later copy works. |
When copies overlap, only the last one started sets copied and error.
Example
Copy payment link shows a check while copied is true and announces the result. When the copy
fails, it shows the link to copy by hand.
Code
"use client";
import { Check, Copy } from "@anantya/icons";
import { announce, Button, useCopyToClipboard } from "@anantya/uix";
const paymentLink = "https://pay.example.com/INV-2026-0142";
export default function CopyPaymentLink() {
const { copy, copied, error } = useCopyToClipboard();
return (
<div className="flex flex-col items-center gap-2 text-sm">
<Button
variant="secondary"
icon={copied ? <Check /> : <Copy />}
onClick={async () => {
if (await copy(paymentLink)) announce("Payment link copied");
else announce("Couldn't copy the payment link", "assertive");
}}
>
Copy payment link
</Button>
{error && (
<p className="text-center">
Couldn't copy it. Select the link and copy it yourself:
<br />
<span className="font-mono break-all select-all">{paymentLink}</span>
</p>
)}
</div>
);
}Notes
- Browsers allow copying only on pages served over HTTPS or from
localhost, and some only right after a click or a key press. Elsewherecopy()resolves to false with anerrorthat says why - Tell screen reader users the result with
announce(), as the example does: a changed icon isn't read - Keep the button's label the same after a copy, so it isn't read again
- On the server,
copy()resolves to false
Changelog
Every change to useCopyToClipboard since 0.1.0 is in the release notes.