Hold to Confirm
A copy-paste buttons component in pure HTML, CSS & vanilla JS. Zero dependencies, framework-agnostic, MIT-licensed.
ButtonsHTMLJavaScriptCSSany framework
Copy into your project
HTML
<button class="nuda-hold">
<span class="nuda-hold__fill"></span>
<span class="nuda-hold__text">Hold to delete</span>
</button>JavaScript
const btn = document.querySelector('.nuda-hold');
let timer = null;
const start = () => {
btn.classList.add('is-holding');
timer = setTimeout(() => {
btn.classList.add('is-confirmed');
btn.dispatchEvent(new CustomEvent('confirm'));
}, 1400);
};
const cancel = () => {
btn.classList.remove('is-holding');
clearTimeout(timer);
};
btn.addEventListener('pointerdown', start);
btn.addEventListener('pointerup', cancel);
btn.addEventListener('pointerleave', cancel);CSS
.nuda-hold__fill {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 0;
background: #ff5e7a;
transition: width 1.4s linear, opacity 0.3s;
}
.nuda-hold.is-holding .nuda-hold__fill { width: 100%; }
.nuda-hold.is-confirmed .nuda-hold__fill { opacity: 0; }
.nuda-hold__text {
position: relative;
z-index: 1;
mix-blend-mode: difference;
color: #fafafa;
}How to use Hold to Confirm
Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.
Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.