Copy button with toast hook
A React hook and button that copy text with a clipboard fallback and show a self-dismissing confirmation toast.
React / Next.jsFeedback and empty statesreactclipboardtoasthook
Live preview
Code
How it works
What it solves
Every developer tool needs a copy button, and most implementations either fail silently on insecure origins or leave the user guessing whether anything happened. This pattern bundles the clipboard write, a fallback for older browsers and a short-lived confirmation message into one hook you can reuse across a page.
How it works
useCopyToast wraps navigator.clipboard.writeText in a try/catch. If the async API is unavailable or rejected (for example in an embedded frame without permission), it falls back to a hidden, read-only textarea and execCommand('copy'). The result decides the toast text. A single timer ref is cleared before each new toast, so rapid clicks extend the message instead of stacking timers, and an effect cleanup clears it on unmount to avoid state updates on a dead component.
CopyButton consumes the hook and renders a polite live region (role="status") so screen readers announce the confirmation without stealing focus.
Adapting it
- Pass a custom label as the second argument to
copyfor context, such as "JSON copied". - Lift the hook to a page and share its
toastvalue if several buttons should reuse one toast element. - Swap the Tailwind classes for your design tokens; only the
statuselement needs to stay mounted.
Pitfalls
- The clipboard API requires a secure context and, in most browsers, a user gesture; call
copydirectly from a click handler. - Keep the toast element in the DOM even when empty, otherwise some screen readers miss the first announcement.
- The fallback is deprecated but still the only option on very old mobile browsers.
How to use it
- Save the file as
components/CopyButton.tsxin a Next.js 15 app (it is a client component). - No packages are required; Tailwind classes are optional.
- Render
<CopyButton value={text} />anywhere, or calluseCopyToast()yourself and rendertoastwhere you like. - Pass a second argument to
copy(value, 'Link copied')to customise the message.
Licence: DEV3 Snippet Licence. Free to use, change and ship in personal and commercial projects. Attribution is appreciated, not required. Please do not redistribute snippets as a collection.