😄

Reactとshadcnでコピーボタンを作る

2024/08/18に公開

Reactとshadcnでコピーボタンを作る。

ChatGPTやClaudeなどでよく見かけるボタンをクリックすると、コードをコピーできるボタンを作る。

実装例

結論としては汚いコードにはなるが、以下のようになる。

TooltipTrigger配下のbuttonタグに

onMouseOver={() => setOpen(true)},
onMouseLeave={() => setOpen(false)}を指定している理由は、クリックすると、ツールチップが消えてしまうので、マウスカーソルをボタンから外さない限り、ツールチップが表示されるようにしています。

import { useState } from "react";
import { CircleCheckIcon, ClipboardIcon } from "lucide-react";

import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/utils/cn";

interface Props extends React.ComponentProps<"button"> {
  copyText?: string;
}

export const CopyButton = (props: Props) => {
  const { copyText = "", className, ...args } = props;
  const [isCopied, setCopied] = useState<boolean>(false);
  const [open, setOpen] = useState<boolean>(false);

  const handleClick = async () => {
    setCopied(false);
    await global.navigator.clipboard.writeText(copyText);
    setTimeout(() => {
      setCopied(true);
    }, 2000);
  };

  return (
    <TooltipProvider>
      <Tooltip defaultOpen={false} open={open}>
        <TooltipTrigger asChild>
          <button
            {...args}
            className={cn("size-6 flex justify-center items-center", className)}
            onClick={() => !isCopied && handleClick()}
            onMouseOver={() => setOpen(true)}
            onMouseLeave={() => setOpen(false)}
          >
            {isCopied ? (
              <CircleCheckIcon className={"size-full"} />
            ) : (
              <ClipboardIcon className={"size-full"} />
            )}
          </button>
        </TooltipTrigger>
        {open && (
          <TooltipContent>
            {isCopied ? "コピーしました" : "コピー"}
          </TooltipContent>
        )}
      </Tooltip>
    </TooltipProvider>
  );
};

実際のコピーしている処理は以下の部分。
async, await、およびglobalがないと正常に動作しないので、忘れず書く

const handleClick = async () => {
    setCopied(copied);
    await global.navigator.clipboard.writeText(copyText);
    setTimeout(() => {
      setCopied(!copied);
    }, 2000);
  };

最後に

コードやER図など間違っていることがあれば、コメントに書いていただけると幸いです。
よろしくお願いいたします。

GitHubで編集を提案

Discussion