React에서 클립보드에 복사하는 올바른 방법 (2024)

발행: (2025년 12월 19일 오후 12:46 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

Cover image for “The Right Way to Copy to Clipboard in React (2024)”

Samitha Widanage

클립보드에 복사하는 것은 간단해 보이죠? 버튼을 클릭하면 텍스트가 클립보드에 들어갑니다. 끝.

하지만 React에서 이를 구현해 본 적이 있다면 그리 간단하지 않다는 것을 알게 될 겁니다. 브라우저 API가 발전했고, 레거시 폴백이 필요하며, 상태를 올바르게 관리하려면 고민이 필요합니다.

저는 이 문제를 한 번에 해결하기 위해 @samithahansaka/clipboard 를 만들었습니다. 이유와 사용 방법을 소개합니다.

기존 솔루션의 문제점

나는 인기 있는 옵션들을 평가했다:

라이브러리 / 접근 방식주간 다운로드 수주요 단점
react-copy-to-clipboard500K+• 훅 API가 없음 (클래스‑컴포넌트 래퍼가 필요함)
• 풍부한 (HTML) 콘텐츠 지원이 없음
• 의미 있는 마지막 업데이트가 몇 년 전임
수동 구현 (Stack Overflow에서 복사‑붙여넣기)• 폴백을 제대로 처리하지 않음
• “복사됨!” 피드백에 대한 상태 관리가 없음
• Next.js나 Remix와 같은 프레임워크에서 SSR 문제 발생
use-clipboard-copy• HTML 콘텐츠 지원이 없음
• 제한된 설정 옵션

결론: 나는 현대적이고, 경량이며, 완전한 무언가가 필요했다.

@samithahansaka/clipboard 소개

npm install @samithahansaka/clipboard

무엇이 다른가

기능이 라이브러리다른 라이브러리
Hooks APISometimes
Component APISometimes
HTML/Rich content
TypeScript✅ First‑classPartial
번들 크기~1 KB2‑5 KB
의존성0Varies
SSR‑안전Often breaks

기본 사용법

import { useCopyToClipboard } from '@samithahansaka/clipboard';

function CopyButton() {
  const { copy, copied } = useCopyToClipboard();

  return (
    <button onClick={() => copy('Hello, World!')}>
      {copied ? '✓ Copied!' : 'Copy'}
    </button>
  );
}

그게 전부입니다. copied 상태는 2초 후에 자동으로 초기화됩니다.

실제 예시: 코드 블록 컴포넌트

import { useCopyToClipboard } from '@samithahansaka/clipboard';

function CodeBlock({ code, language }: { code: string; language: string }) {
  const { copy, copied, error } = useCopyToClipboard({
    successDuration: 2000,
  });

  return (
    <div className="code-block">
      <div className="header">
        <span>{language}</span>
        <button
          onClick={() => copy(code)}
          className={copied ? 'success' : ''}
        >
          {copied ? '✓ Copied!' : 'Copy'}
        </button>
      </div>
      <pre>{code}</pre>
      {error && <div className="error">Copy failed</div>}
    </div>
  );
}

/* Additional snippet example */
{/* {error ? 'Failed!' : copied ? 'Copied!' : 'Copy'} */}

추가 스니펫 예시

이 컴포넌트는 코드 스니펫을 표시하고, 복사 버튼을 통해 2 초 동안 성공 상태를 표시하며 복사 오류를 우아하게 처리합니다.

풍부한 HTML 콘텐츠 복사

대부분의 라이브러리가 여기서 한계에 부딪힙니다. Google Docs나 이메일에 올바르게 붙여넣어지는 서식 있는 텍스트를 복사해야 하나요?

const { copy } = useCopyToClipboard();

// Copy both plain text **AND** HTML
copy({
  text: 'Hello, World!',          // Fallback for plain‑text apps
  html: '**Hello, World!**'       // Rich content for compatible apps
});

붙여넣을 때:

  • Notepad / Terminal: Hello, World!
  • Google Docs / Email: Hello, World! (굵게)

토스트 라이브러리와의 통합

모든 알림 라이브러리와 원활하게 작동합니다:

import { useCopyToClipboard } from '@samithahansaka/clipboard';
import { toast } from 'sonner'; // or react-hot-toast, etc.

function ShareButton({ url }: { url: string }) {
  const { copy } = useCopyToClipboard({
    onSuccess: () => toast.success('Link copied!'),
    onError: () => toast.error('Failed to copy'),
  });

  return (
    <button onClick={() => copy(url)}>
      Share
    </button>
  );
}

Simple Cases에 대한 Component API

렌더 프롭스를 선호하시나요? 컴포넌트 API도 있습니다:

import { CopyButton } from '@samithahansaka/clipboard';

function App() {
  return (
    <CopyButton>
      {/* children can be a custom button or any element */}
      Copy
    </CopyButton>
  );
}
<CopyButton>
  {({ copy, copied }) => (
    <button onClick={copy}>
      {copied ? 'Done!' : 'Copy'}
    </button>
  )}
</CopyButton>

내부 작동 방식

라이브러리는 점진적 향상을 사용합니다:

  1. 최신 브라우저 (Chrome 76+, Firefox 63+, Safari 13.1+):
    전체 HTML 지원을 위해 navigator.clipboard.write()를 사용합니다.
  2. 다소 최신 브라우저:
    일반 텍스트 복사를 위해 navigator.clipboard.writeText()로 대체합니다.
  3. 레거시 브라우저 (IE 11, 구형 Safari):
    숨겨진 <textarea>와 함께 document.execCommand('copy')를 사용합니다.

이 모든 것을 직접 생각할 필요가 없습니다. 그냥 작동합니다.

TypeScript 지원

전체 타입 정의가 포함되어 있습니다:

import {
  useCopyToClipboard,
  CopyButton,
  type CopyContent,
  type ClipboardItem,
} from '@samithahansaka/clipboard';

// TypeScript knows exactly what `copy()` accepts
const { copy } = useCopyToClipboard();

copy('string');                         // ✅
copy({ text: 'hi' });                  // ✅
copy({ text: 'hi', html: '**hi**' }); // ✅
copy(123);                             // ❌ Type error

SSR‑Safe

다음과 같은 Next.js, Remix, Gatsby 또는 모든 SSR 프레임워크와 바로 사용할 수 있습니다:

  • “window is not defined” 오류가 발생하지 않습니다.
  • 동적 import가 필요하지 않습니다.
  • 그냥 일반적으로 사용하면 됩니다.
import { useCopyToClipboard } from '@samithahansaka/clipboard';

번들 크기

전체 라이브러리는 ~1 KB gzipped 입니다. 비교를 위해:

Library크기 (gzipped)
@samithahansaka/clipboard~1 KB
react-copy-to-clipboard~2 KB
use-clipboard-copy~3 KB
Back to Blog

관련 글

더 보기 »

궁극의 React Hooks 가이드

markdown !TenE Organization 프로필 이미지https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads....