Hold to Confirm

홀드 투 컨펌

A safety net for irreversible actions like delete or pay — the button only fires once you've held it long enough to fill.

Also known as: Press and hold to confirm
···
html
<button class="hold" id="holdbtn"><span class="hbar" id="hbar"></span><span class="htxt">Hold to delete</span></button>
css
.fx-dot{position:absolute;left:0;top:0;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;
  background:var(--accent);box-shadow:0 0 0 5px color-mix(in srgb,var(--accent) 18%,transparent),0 2px 6px rgba(0,0,0,.3);
  pointer-events:none;z-index:9999;transition:opacity .25s}
.hold{position:relative;overflow:hidden;padding:16px 26px;border-radius:12px;border:2px solid var(--line);
  background:var(--surface);cursor:pointer;font-weight:700;color:var(--fg);font-size:clamp(11px,3.4vmin,14px);
  width:min(80%,220px)}
.hbar{position:absolute;left:0;top:0;bottom:0;width:0%;background:color-mix(in srgb,var(--accent-2) 70%,transparent)}
.htxt{position:relative;z-index:1}
.hold.done{border-color:var(--accent-2)}
js
const fxDot=document.createElement('div');fxDot.className='fx-dot';document.body.appendChild(fxDot);
let fxAuto=true,fxX=innerWidth/2,fxY=innerHeight/2;
function fxHide(){fxDot.style.opacity='0';}
addEventListener('pointerdown',()=>{fxAuto=false;fxHide();},{capture:true});
addEventListener('pointermove',e=>{fxAuto=false;fxHide();fxX=e.clientX;fxY=e.clientY;},{capture:true});
function fxWalk(x,y,ms){
  return new Promise(res=>{
    const sx=fxX,sy=fxY,start=performance.now();
    function step(now){
      if(!fxAuto)return res();
      const p=Math.min(1,(now-start)/ms),e=1-Math.pow(1-p,3);
      fxX=sx+(x-sx)*e;fxY=sy+(y-sy)*e;
      fxDot.style.transform='translate('+fxX+'px,'+fxY+'px)';
      if(p<1)requestAnimationFrame(step);else res();
    }
    requestAnimationFrame(step);
  });
}
function fxWait(ms){
  return new Promise(res=>{
    const start=performance.now();
    function step(now){ if(!fxAuto)return res(); if(now-start<ms)requestAnimationFrame(step);else res(); }
    requestAnimationFrame(step);
  });
}

const hbtn=document.getElementById('holdbtn');
const hbar=document.getElementById('hbar');
const HOLD_MS=1100;
let raf=null;
function tick(start){
  const p=Math.min(1,(performance.now()-start)/HOLD_MS);
  hbar.style.width=(p*100)+'%';
  if(p<1) raf=requestAnimationFrame(()=>tick(start));
  else complete();
}
function hstart(){ raf=requestAnimationFrame(()=>tick(performance.now())); }
function hcancel(){ if(raf) cancelAnimationFrame(raf); raf=null; hbar.style.width='0%'; hbtn.classList.remove('done'); }
function complete(){
  raf=null; hbar.style.width='100%'; hbtn.classList.add('done');
  setTimeout(()=>{ hbtn.classList.remove('done'); hbar.style.width='0%'; },900);
}
hbtn.addEventListener('pointerdown',()=>{ fxAuto=false; fxHide(); hstart(); });
addEventListener('pointerup',()=>{ if(raf) hcancel(); });
addEventListener('pointercancel',()=>{ if(raf) hcancel(); });
async function autoSeq(){
  while(fxAuto){
    const r=hbtn.getBoundingClientRect();
    await fxWalk(r.left+r.width/2, r.top+r.height/2, 500); if(!fxAuto) break;
    hstart();
    await fxWait(HOLD_MS+150); if(!fxAuto) break;
    await fxWait(700); if(!fxAuto) break;
    await fxWalk(innerWidth*(0.2+Math.random()*0.6), innerHeight*(0.2+Math.random()*0.6), 400);
    await fxWait(300);
  }
}
autoSeq();

Structurally it's the same as long-press — track elapsed time from `pointerdown` and drive a fill animation. The difference is intent: long-press opens a secondary menu, while hold-to-confirm exists specifically to prevent accidental triggers.

So it typically uses a more alarming visual language (reds/oranges, a bar that fills the whole button) and often shows "release to cancel" while filling. A stray tap — `pointerdown` immediately followed by `pointerup` — must never fire it.

After it fires, show brief completion feedback (a checkmark, a color swap) before returning to rest, so the person can be certain the action actually went through.

When to use

Use it for account deletion, payment confirmation, irreversible deletes — anything that deserves a beat of hesitation. For everyday confirmations, a plain confirm modal is enough.