인터랙션

[Hold to confirm] 꾹 눌러야 실행되는 위험 작업 확인 버튼

실수 클릭으로 삭제되는 사고를 막는 press-and-hold 버튼. 누르고 있으면 링이 차오르고, 끝까지 채워야 실행됩니다.

ReactPointer EventsrequestAnimationFrameSVG stroke-dashoffsetARIA slider
라이브 데모
새 탭에서 열기
데모 불러오는 중…

제작 과정

한 줄 요약 - "삭제" 같은 위험한 버튼을 한 번 클릭이 아니라 잠깐 누르고 있어야 실행되게 만들어, 실수로 누르는 사고를 막는 버튼입니다.

이럴 때 필요해요

목록에서 휴지통 아이콘을 무심코 눌렀다가 데이터가 날아간 경험, 한 번쯤 있으시죠. "정말 삭제할까요?" 확인 모달을 띄우는 방법도 있지만, 모달은 흐름을 끊고 매번 한 번 더 클릭하게 만들어 귀찮습니다. 길게 눌러 확인은 모달 없이도 "의도가 분명한 행동"만 통과시킵니다.

어떻게 동작하나

  1. 버튼을 누르면 "누르기 시작한 시각"을 기록하고, 매 화면 프레임마다 "지금까지 지난 시간 / 목표 시간"으로 진행률을 계산합니다.
  2. 진행률이 링(원형 게이지)을 채우다가 100%에 닿는 순간 실제 동작(삭제)이 실행됩니다.
  3. 끝까지 가기 전에 손을 떼면 진행률을 0으로 부드럽게 되돌립니다. 다시 누르면 남아 있던 지점부터 이어서 차오릅니다.

핵심은 이거예요

진행률을 "프레임마다 조금씩 더하는" 방식이 아니라 "시작 시각과 현재 시각의 차이"로 매번 다시 계산한다는 점입니다. 이렇게 하면 화면이 잠깐 버벅여도(프레임이 밀려도) 오차가 쌓이지 않아 항상 정확히 설정한 시간에 채워집니다.

놓치기 쉬운 것

  • 키보드 사용자를 위해 Enter/Space로도 눌러야 하는데, 키를 누르고 있으면 OS가 같은 입력을 자동 반복으로 보냅니다. 첫 입력만 "누르기 시작"으로 받고 반복은 무시해야 진행이 처음부터 다시 시작되지 않습니다.
  • 버튼 위에서 누른 채 손가락을 밖으로 끌면 떼는 신호를 놓칠 수 있어, 포인터 캡처와 leave/cancel까지 모두 멈춤으로 처리해야 합니다.
  • 컴포넌트가 사라질 때 진행 루프를 정리하지 않으면 보이지 않는 곳에서 계속 돌며 메모리가 샙니다.

이런 곳에 써요

  • 계정 삭제, 결제 취소처럼 되돌리기 어려운 위험 작업 버튼
  • 모바일 앱에서 "길게 눌러 전송 취소"나 긴급 정지 같은 신중함이 필요한 동작

소스 코드

· 데모 페이지에서 자동 추출
import type { Metadata } from "next";
import { HoldToConfirmDemo } from "./-components/HoldToConfirmDemo";

export const metadata: Metadata = {
  title: "길게 눌러 확인 버튼 (데모)",
  description:
    "위험 작업 버튼을 누르고 있으면 진행 링이 차오르고, 끝까지 채우면 발화. 도중에 떼면 부드럽게 되돌아감. Pointer Events + 키보드 + requestAnimationFrame.",
  robots: { index: false, follow: false },
};

export default function Page() {
  return (
    <main className="flex min-h-[100dvh] items-center justify-center bg-gradient-to-br from-rose-50 via-white to-orange-50/60">
      <HoldToConfirmDemo />
    </main>
  );
}
24조회수

댓글