프로젝트/Next+TypeScript

[Coworkers] 클립보드 복사 (Trouble Shooting)

dev-hpk 2025. 1. 27. 17:07

오늘 작업에는 클립보드를 이용하는 부분이 있습니다❗

멤버 초대 모달 UI

 

유저 정보 모달 UI

멤버 초대 모달의 '링크 복사하기' 버튼을 클릭하면 URL을 클립보드에 복사하고, 유저 정보 모달의 '이메일 복사하기' 버튼을 클릭하면 유저의 이메일을 복사해요✨

 

클립보드를 어떻게 구현해야 할까요🤔 라이브러리를 찾아보기 전에 저의 해답지인 MDN을 찾아볼게요!

Clipboard API 설명 - 출처 MDN

 

Clipboard API의 writeText() 메서드를 사용하면 특정 text를 클립보드에 저장하고 Promise를 반환한다고 하네요😀

Clipboard API - writeText 사용법

async function writeClipboardText(text) {
  try {
    await navigator.clipboard.writeText(text);
  } catch (error) {
    console.error(error.message);
  }
}

링크 복사 - writeText 적용

const handleClick = async () => {
  await navigator.clipboard.writeText(`${SERVER_URL}?token=${token}`);
  closeModal();
};

<Button className="w-full text-text-inverse" onClick={handleClick}>
  링크 복사하기
</Button>;

이메일 복사 - writeText 적용

const handleClick = async () => {
  await navigator.clipboard.writeText(member.userEmail);
  closeModal();
};

<Button className="w-full text-text-inverse" onClick={handleClick}>
  이메일 복사하기
</Button>;

결과 - 클립보드 복사

클립보드 적용 결과

 

PC에서 링크와 이메일 모두 잘 복사되네요! 하지만 여기서 끝내면 안 되겠죠.

PC에서 잘 동작하던 기능들이 OS와 브라우저에 따라서 제대로 동작하지 않은 경우를 경험했잖아요🤔

아니나 다를까 노트북과 아이폰 Safari 브라우저로 확인했더니 에러가 발생하네요😭

🚨 문제 상황

Clipboard API 에러

 

MDN의 cilpboard API를 확인해 보니 localhost나 HTTPS 환경에서만 사용할 수 있다고 하네요😥

clipboard API - MDN

 

코드를 통해 직접 확인해 봐야겠죠🤔

const handleClick = async () => {
    if (!navigator.clipboard) {
      alert('현재 브라우저에서 클립보드 복사를 지원하지 않습니다.');
      return;
    }
    await navigator.clipboard.writeText(member.userEmail);
    closeModal();
  };

에러 확인 결과

🚩 문제 해결 방법

1️⃣ Document.execCommand() : 지원 중단

2️⃣ react-copy-to-clipboard

 

2️⃣ react-copy-to-clipboard 라이브러리를 사용하면 라이브러리에서 제공하는 간단한 컴포넌트를 이용해 복사 기능을 구현할 수 있지만, 저희 프로젝트는 React 19 버전이라 사용이 불가능했어요😭

react-copy-to-clipboard 라이브러리 pr

 

execCommand() 지원중단

 

안타깝게도 위 메서드는 지원 중단되어 권장되지 않는다고 하네요😭 하지만 저에게는 방법이 없습니다. 찾아보니 execCommand() 메서드가 아직 많은 브라우저에서 동작하네요.

execCommand 브라우저 호환성 표

 

🌈 문제 해결

execCommand를 이용한 텍스트 복사 함수

const copyWithExecCommand = (text: string) => {
  const textArea = document.createElement('textarea');
  textArea.value = text;
  document.body.appendChild(textArea);
  textArea.select();
  document.execCommand('copy');
  document.body.removeChild(textArea);
};

링크 복사 - writeText 적용

const handleClick = async () => {
  if (navigator.clipboard && navigator.clipboard.writeText) {
    await navigator.clipboard.writeText(`${SERVER_URL}?token=${token}`);
  } else {
    copyWithExecCommand(`${SERVER_URL}?token=${token}`);
  }
  closeModal();
};

이메일 복사 - writeText 적용

const handleClick = async () => {
  if (navigator.clipboard && navigator.clipboard.writeText) {
    await navigator.clipboard.writeText(member.userEmail);
  } else {
    copyWithExecCommand(member.userEmail);
  }

  closeModal();
};

결과 - 클립보드 복사

문제 해결 후 클립보드 복사

 

navigator.clipboard를 호환하는 https에서는 기존과 동일하게 동작합니다.
navigator.clipboard를 호환하지 않는 http에서는 아래 과정을 거치게 됩니다.

  1. 값을 저장하기 위한 textarea라는 요소를 만들고 value 속성에 복사할 값을 할당
  2. textarea 요소를 html body에 추가하고 선택
  3. execCommand 메서드를 사용해 클립보드에 텍스트를 복사
  4. textarea 요소를 html body에서 삭제

Document.execCommand()가 지원 중단되었다고는 하지만, 덕분에 navigator.clipbaord를 호환하지 않는 http 환경에서도 안전하게 클립보드 복사 기능을 구현할 수 있게 되었어요😊