복사 버튼을 누르자 “복사 완료”가 떴는데, 붙여 넣으니 이전 문장이 나온다면? 버튼의 표정이 기능보다 먼저 퇴근한 셈입니다. 텍스트 복사는 성공 문구보다 실패했을 때의 출구까지 설계해야 끝납니다. 이 글은 공개 문서를 바탕으로 만든 구현·검수 가이드이며 특정 서비스에서 직접 겪은 장애 기록이 아닙니다.

먼저 정할 완료 기준: 클릭이 아니라 처리 결과

navigator.clipboard.writeText(text)는 비동기로 동작합니다. 반환된 Promise가 이행된 뒤에만 “복사했습니다”를 보여 주세요. 호출 직후 성공 상태로 바꾸거나, finally에서 무조건 성공 문구를 넣으면 실패도 성공으로 포장됩니다. 다만 API 성공은 다른 앱에 붙여 넣기까지 완료했다는 뜻은 아닙니다. 수동 검수에서는 별도 입력란에 붙여 넣은 값까지 비교합니다.

공식 근거: MDN writeText()의 반환값과 예외 ↗

안 될 때는 환경 → 동작 → 결과 순서로 좁히세요

  • 환경: window.isSecureContext와 navigator.clipboard?.writeText 존재를 확인합니다. HTTPS 배포 주소와 로컬 개발 주소를 구분해 기록합니다. localhost에서 됐다고 일반 HTTP 주소에서도 된다고 결론 내리지 않습니다.
  • 동작: 사용자가 누른 버튼의 이벤트에서 준비된 텍스트를 복사합니다. 복사 전에 긴 요청을 기다리게 하기보다, 텍스트를 미리 준비하고 준비된 뒤 버튼을 활성화하는 구조를 우선 검토합니다.
  • 결과: writeText()의 이행과 거부를 나눕니다. NotAllowedError라는 이름만 보고 “사용자가 권한을 거절했다”고 단정하지 말고 실행 환경과 호출 경로를 함께 확인합니다.

브라우저의 권한 처리와 사용자 활성화 요건은 동일하지 않습니다. MDN은 Chromium과 Firefox·Safari의 차이를 별도로 설명합니다. 모든 브라우저에서 clipboard-write 권한 조회가 된다고 가정하지 마세요. iframe 안이라면 상위 문서의 보안 컨텍스트와 해당 브라우저의 Permissions Policy 적용도 확인하되, 복사 하나를 위해 사이트 전체 권한을 무작정 넓히지 않습니다.

공식 근거: MDN Clipboard API 보안 고려사항 ↗

공식 근거: MDN 보안 컨텍스트와 localhost ↗

같은 지니안 캐릭터가 자물쇠, 누르는 버튼, 체크된 클립보드 옆에 각각 앉아 있는 그림
AI 생성 일러스트 · 보안 컨텍스트, 사용자 동작, 처리 결과를 따로 확인하는 세 가지 관점을 상징합니다. 실제 브라우저 화면이 아닙니다.

작은 구현 예시: 원문은 남기고 성공은 기다리기

다음 예시는 복사할 짧은 공개 문장을 미리 준비한 경우입니다. HTML 뒤에서 스크립트를 실행합니다. 읽기 권한을 요구하지 않고, 원문을 항상 선택할 수 있게 남깁니다. 실패 시에는 성공처럼 버튼을 꾸미지 않으며 버튼을 다시 사용할 수 있게 돌려놓습니다. 실제 제품에서는 기존 포커스·상태 표시 규칙과 함께 검토하세요.

<label for="copy-source">복사할 문장</label>
<textarea id="copy-source" readonly>샘플 안내 문장</textarea>
<button id="copy-button" type="button">문장 복사</button>
<p id="copy-status" role="status"></p>
<script>
const source = document.querySelector('#copy-source');
const button = document.querySelector('#copy-button');
const status = document.querySelector('#copy-status');
let busy = false;
button.addEventListener('click', async () => {
  if (busy) return;
  busy = true;
  button.setAttribute('aria-disabled', 'true');
  status.textContent = '복사 중입니다.';
  try {
    if (!window.isSecureContext || !navigator.clipboard?.writeText) {
      throw new Error('copy-unavailable');
    }
    await navigator.clipboard.writeText(source.value);
    status.textContent = '복사했습니다. 원하는 곳에 붙여 넣으세요.';
  } catch {
    status.textContent = '자동 복사를 완료하지 못했습니다. 위 문장을 직접 선택해 복사해 주세요.';
  } finally {
    busy = false;
    button.removeAttribute('aria-disabled');
  }
});
</script>

aria-disabled만으로 클릭이 차단되는 것은 아니어서 busy 검사를 함께 둡니다. readonly 영역은 비활성화된 입력란과 달리 원문을 선택하는 출구로 남깁니다. 예시는 클립보드를 다시 읽어 성공을 증명하려 하지 않습니다. 복사 기능에 불필요한 읽기 권한과 사적인 클립보드 내용을 끌어오지 않기 위해서입니다.

실패 메시지는 원인 추측보다 다음 행동을

  • 피할 문구: “권한을 허용하면 무조건 됩니다.” 확인하지 않은 원인과 결과를 약속합니다.
  • 권장 문구: “자동 복사를 완료하지 못했습니다. 아래 내용을 직접 선택해 복사해 주세요.” 실패 사실과 다음 행동만 안내합니다.
  • 원문이 길다면: 읽기 전용 영역을 충분히 넓히고 줄바꿈을 보존합니다. 모바일에서 길게 눌러 선택할 수 있는지도 별도로 확인합니다.
지니안 캐릭터가 자동 복사 실패 표시 옆에서 직접 선택할 수 있는 텍스트 영역을 가리키는 그림
AI 생성 일러스트 · 자동 복사가 실패해도 직접 선택할 원문을 남기는 대안을 표현했습니다. 실제 기능 실행 결과는 아닙니다.

배포 전에 채울 여섯 줄 검수표

테스트에는 개인정보나 인증 코드 대신 “복사 확인 A 두 번째 줄” 같은 합성 문장을 사용하세요. 테스트 더블로 Promise를 성공·실패시킨 검사는 화면 상태를 검증할 뿐, 실제 OS 클립보드나 브라우저 권한 검증을 대신하지 않습니다.

  • 정상 복사: 실제 HTTPS 주소에서 버튼을 누른 뒤 별도 입력란에 붙여 넣고 두 줄이 같은지 확인한다.
  • 실패 경로: 테스트 환경에서 writeText 거부를 주입하고 성공 문구가 나오지 않는지 확인한다.
  • 미지원 경로: API가 없는 테스트 조건에서 직접 선택 안내가 나타나는지 확인한다.
  • 반복 클릭: 처리 중 여러 번 눌러도 요청이 겹치지 않고, 완료·실패 후 다시 시도할 수 있는지 확인한다.
  • 입력 방식: Tab으로 버튼에 도달해 Enter·Space로 실행하고 상태 안내와 포커스를 확인한다.
  • 대상 환경: 지원할 데스크톱·모바일 브라우저에서 각각 검수한다. 인앱 브라우저나 iframe을 지원한다면 별도 항목으로 남긴다.
검수 기록 양식
날짜 / 배포 주소 / 브라우저·버전 / OS:
실행 위치: 최상위 페이지 또는 iframe
합성 입력값:
누른 직후 표시 / 처리 후 표시:
붙여 넣은 값과 원문 일치: 예·아니요·미검증
실패 시 직접 선택 가능: 예·아니요·미검증
재시도·키보드 확인:
남은 제한과 다음 조치:

AI에게 요청할 때도 실패를 명세에 넣으세요

텍스트 복사 버튼을 만들어 주세요. 공개 문장은 클릭 전에 준비하고, writeText의 Promise 이행 후에만 성공을 안내하세요. 실패와 미지원에서는 직접 선택할 원문을 남기세요. 기존 포커스 흐름을 유지하고 연속 클릭을 제어하세요. 테스트 더블 검사와 실제 브라우저·OS 검증 결과를 분리해서 보고해 주세요.

완료 기준은 “복사 버튼이 있다”가 아니라 “복사됐는지 정직하게 알려 주고, 안 됐을 때도 사용자가 빠져나갈 수 있다”입니다. 체크 아이콘은 마지막에 출근시켜도 늦지 않습니다.

이어서 읽기: 바이브 코딩 배포 전, 키보드로 끝까지 써 보기 ↗

공식 구현 배경: WebKit Async Clipboard API (2020-06-23) ↗

자료 확인: 2026년 10월 21일. 브라우저 동작은 버전과 문서 환경에 따라 달라질 수 있으므로 실제 지원 환경에서 재검증하세요. 그림은 승인된 지니안 캐릭터를 참조한 AI 생성 개념 일러스트입니다.