useCopyToClipboard

useCopyToClipboard

useCopyToClipboard is a custom hook to copy text to the clipboard with optional callbacks and auto-reset functionality.


Syntax

const { copied, error, copy } = useCopyToClipboard(options?: CopyToClipboardOptions);

Props

The hook accepts an optional object of type CopyToClipboardOptions:

PropertyTypeDefaultDescription
resetTimenumber1500 (ms)Time in milliseconds to reset the copied state.
onSuccess(copiedText: string) => voidundefinedCallback function triggered when text is successfully copied to the clipboard.
onError(error: Error) => voidundefinedCallback function triggered when an error occurs during the copy operation.

Return

An object containing the following properties:

KeyTypeDescription
copiedbooleanIndicates whether the text was successfully copied to the clipboard.
errorError | nullHolds the error object if the copy operation fails; otherwise, it is null.
copy(text: string) => Promise<void>A function that triggers the copy operation. Accepts the text to be copied as an argument.

The Hook

useCopyToClipboard.ts
import { useCallback, useState } from "react";
 
interface CopyToClipboardState {
  copied: boolean;
  error: Error | null;
}
interface CopyToClipboardStateReturnType extends CopyToClipboardState {
  copy: (text: string) => Promise<void>;
}
interface CopyToClipboardOptions {
  resetTime?: number;
  onSuccess?: (copiedText: string) => void;
  onError?: (error: Error) => void;
}
 
export function useCopyToClipboard(
  options: CopyToClipboardOptions = {}
): CopyToClipboardStateReturnType {
  const { resetTime = 1500, onSuccess, onError } = options;
  const [state, setState] = useState<CopyToClipboardState>({
    copied: false,
    error: null,
  });
  const copy = useCallback(async (text: string) => {
    try {
      if (!navigator?.clipboard) {
        throw new Error("Clipboard API not supported");
      }
      await navigator.clipboard.writeText(text);
      setState({ copied: true, error: null });
      onSuccess?.(text);
 
      setTimeout(() => {
        setState((prev) => ({
          ...prev,
          copied: false,
        }));
      }, resetTime);
    } catch (error) {
      const copyError =
        error instanceof Error ? error : new Error("Failed to copy");
      setState({ copied: false, error: copyError });
      onError?.(copyError);
    }
  }, []);
 
  return { ...state, copy };
}

Usage

Basic Example

import React from "react";
import { useCopyToClipboard } from "./hooks";
 
function CopyDemo() {
  const { copied, error, copy } = useCopyToClipboard();
 
  async function handleCopy() {
    await copy("Hello, World!");
  }
 
  return (
    <div>
      <button onClick={handleCopy}>{copied ? "Copied!" : "Copy Text"}</button>
      {error && <p>Error: {error.message}</p>}
    </div>
  );
}

Example with Callbacks and Custom Reset Time

import React from "react";
import { useCopyToClipboard } from "./hooks";
 
function CopyWithCallbacks() {
  const { copied, error, copy } = useCopyToClipboard({
    resetTime: 3000,
    onSuccess: (text) => alert(`Successfully copied: ${text}`),
    onError: (error) => alert(`Error copying: ${error.message}`),
  });
 
  async function handleCopy() {
    await copy("Sample text for clipboard!");
  }
 
  return (
    <div>
      <button onClick={handleCopy}>
        {copied ? "Copied!" : "Copy to Clipboard"}
      </button>
      {error && <p style={{ color: "red" }}>Error: {error.message}</p>}
    </div>
  );
}

Specifications

This hook utilizes the Clipboard API (opens in a new tab) to perform clipboard operations. Ensure that the browser supports this API for consistent functionality.


See Also

Last updated on November 23, 2024