Over the past year, I've tried and started to use "hold-to-confirm" buttons in our projects. Inspired by game design principles, this simple change has made a world of difference in UX, functionality, and my mental health.
The Problem with Confirmation Dialogs
"I accidentally deleted... Can you find it in your backups?" says every user ever.
Yeah, "accidentally," sure...
But since I think that confirmation dialogs are a bad design in general, these requests are annoying, but I get it. It's just proof that the traditional approach is ineffective in preventing terminal actions a user doesn't really want to make.
Confirmation pop-ups - whether browser-based or custom - are often more annoying than helpful. They interrupt the user's flow and can lead to "confirmation fatigue," where users habitually click through dialogs without truly processing the action they're about to take.
The Advantage of Hold-to-Confirm Buttons
Frankly, for how simple it is to implement, it's a game-changer.
Hold-to-confirm buttons require the user to press and hold a button for a predetermined amount of time (e.g., 1 to 5 seconds) to execute an action. This method offers several benefits:
- Intentionality: Holding a button creates a continuous period where the user subconsciously but actively considers their action.
- Reduced Errors: By requiring sustained interaction, accidental clicks are none. Really, zero - we've had none since implementation, unlike tens of requests per month with confirmation dialogs.
- Enhanced UX: It provides a smoother, less intrusive experience compared to disruptive confirmation dialogs.
How It Works
When a user initiates a hold-to-confirm action, a visual indicator (like a progress bar) fills up over the hold period. If the user releases the button before completion, the action is canceled. This simple mechanism effectively replaces the need for a secondary confirmation step.
Real-World Implementation and Results
We first implemented hold-to-confirm buttons in our Grace projects for deletion actions. We set a 3-second hold time with a filling progress bar of a contrasting color. This duration proved sufficient without being tedious.
3 seconds? So long? Well... surprisingly, confirmation dialogs often take longer due to the extra click elsewhere on the screen and the reading involved.
I tried this duration, felt it was right and I was correct - works ‘till this day.
The Outcome?
- Immediate Success: We saw a total mitigation of accidental deletions.
- Positive Feedback: Only a few users needed clarification on the new mechanism.
- Improved Satisfaction: Users appreciated it over dialogs.
Building on this success, we now use hold-to-confirm buttons by default for any action that changes the state of an item. For instance, in Grace Manager, actions like pausing a task or sending an email require holding the button for 1 to 1.5 seconds.
Determining the Appropriate Hold Duration
It's not as tricky as it sounds. Here's how we go about it:
- Terminal Actions (e.g., Deletions): 3 seconds. These actions are irreversible and may affect user data significantly.
- Critical Actions Affecting Others: Up to 5 seconds. For actions like canceling an invoice that notifies customers, a longer hold time ensures a higher level of deliberate intent. It can get a little bit annoying, which is the purpose.
- Easily Reversible Actions: 1 to 1.5 seconds. For actions like unpublishing articles, shorter hold times maintain efficiency while still requiring intent and thought.
These durations strike a balance between safety and usability, giving users enough time to consider their actions without causing frustration.
The Importance of Visual Feedback
Visual cues are the most important for the effectiveness of hold-to-confirm buttons:
- Progress Indicators: A filling bar or countdown communicates that the button needs to be held.
- Immediate Feedback: If the button is clicked (not held), a brief movement of the progress bar signals that the user should hold the button.
- Completion Animation: A subtle effect after the hold is complete confirms that the action has been executed.
Avoid overwhelming animations that distract the user. The goal is to keep the user informed with as less cognitive engagement as possible to prevent diverting their attention from the decision at hand.
How We Do It
Our buttons fill up from left to right with a contrasting color and have a countdown in precision of a thousandth of a second. I don't generally recommend a countdown. For Grace, it's more of an aesthetic since it's inspired by futuristic, tech, and cyberpunk styles, which are largely defined by precision. We also add a slight "press" animation after completion.
If the hold is canceled midway, the bar retracts much faster to zero, perfectly indicating a return to the initial state.
The Psychology Behind It
Hold-to-confirm buttons engage the user's cognitive processes more effectively than confirmation dialogs (which pretty much don't at all):
- Continuous Engagement: Holding requires sustained attention, allowing the user to fully process the impending action.
- Reduced Cognitive Load: Eliminates the need to read and interpret additional text in confirmation dialogs—and for developers, there's no need to write that content.
- Intentional Actions: Users are less likely to perform unintended actions, as the process feels and is more deliberate.
In contrast, confirmation dialogs can lead to habitual clicking without genuine consideration, increasing the risk of mistakes.
Implementing Hold-to-Confirm in Your Projects
class DexMiniButtonsItem {
El;
HoldingTimeMs = 1000;
HoldingTimeout;
SetHoldingEvents() {
let start_time;
let btn = this.El.find('.DexMiniButtonsBtn');
const update_timer = () => {
let elapsed = performance.now() - start_time;
let remaining = this.HoldingTimeMs - elapsed;
if (remaining <= 0) {
btn.dataset.remaining = '0 s';
return;
}
btn.dataset.remaining = (remaining / 1000).toFixed(3) + ' s';
requestAnimationFrame(update_timer);
};
let start_event = e => {
e.preventDefault();
this.El.style.setProperty('--holding-duration', this.HoldingTimeMs + 'ms');
this.El.dataset.holding = '1';
if (this.HoldingTimeout) {
clearTimeout(this.HoldingTimeout);
this.HoldingTimeout = null;
}
start_time = performance.now();
update_timer();
this.HoldingTimeout = setTimeout(() => {
this.HoldingTimeout = null;
this.El.dataset.holding = 'finished';
if (navigator.vibrate) navigator.vibrate([150, 0]);
this.AfterHold();
}, this.HoldingTimeMs);
};
this.addEventListener('pointerdown', start_event);
this.addEventListener('touchstart', start_event);
window.addEventListener('pointerup', e => {
if (this.HoldingTimeout) {
e.preventDefault();
clearTimeout(this.HoldingTimeout);
cancelAnimationFrame(update_timer);
if (this.El.dataset.holding !== 'finished') {
this.El.dataset.holding = 'let-go';
}
this.HoldingTimeout = null;
}
});
}
}
<div class="HoldingButton">
<button>
<div class="Label" data-type="label"></div>
<div class="ActionLine" data-type="number-text"></div>
</button>
</div>
.DexMiniButtonsBtnBox.HoldingButton {
--holding-duration: 1000ms;
}
.HoldingButton button:hover .ActionLine, .HoldingButton[data-holding="1"] .ActionLine {background: var(--yellow); color: var(--dark);}
.HoldingButton button {position: relative;}
.HoldingButton button::after {position: absolute; content: attr(data-remaining); left: 0; top: 0; bottom: 0; width: 0; background: var(--yellow); transition: var(--holding-duration) linear; transition-property: width; z-index: -1; overflow: hidden; text-indent: 10px; text-align: left; font-size: 16px; font-weight: 600; display: flex; align-items: center; color: var(--dark); white-space: nowrap;}
.HoldingButton[data-holding="let-go"] button::after {transition-duration: 100ms;}
.HoldingButton[data-holding="1"] button::after {width: 100%;}
.HoldingButton[data-holding="finished"] button {animation: HoldingBtnFinished 75ms running; animation-timing-function: linear; animation-iteration-count: 1;}
.HoldingButton[data-holding="finished"] button::after {width: 100%; transition-property: background-color; content: '';}
Conclusion
Hold-to-confirm buttons offer a superior alternative to traditional confirmation dialogs by:
- Enhancing user intentionality.
- Reducing accidental actions.
- Streamlining the user experience.
By rethinking how we approach confirmations, we can create applications that are not only more user-friendly but also more effective in preventing unintended consequences.
Have you used hold-to-action buttons?
Do you get those "accidentally deleted" notes from users?
What do you think about confirmation dialogs or holding buttons?
Top comments (4)
This would make a neat html web component.
Adding a
span
withrole=alert
to speak the countdown/countup and provide non-visual feedback. It could also change to "press and hold button" or something to provide feedback.I am not sure if this span can be in the shadow dom and still work though and a quick google/duckduckgo search doesn't answer my question.
Agreed! It would be awesome to see a special button tag for holding in browsers directly.
But I don't think we will, not anytime soon. As a UX element, it needs wide-spread adoption first.
About the , I think should work. But for "surely work", I can recommend to take the code in the article and create your own reusable piece and put any tags needed in ;)
Hi Tom:
Yup, I think your
<span>
was missing some backticks.Having a web-component to enhance the button may be the way to improve adoption by making it trivial to implement. Time to play around on codepen some weekend.
Also, I found the following article: kirupa.com/html5/press_and_hold.htm with a similar idea.
Sure, could be the gif, could actually miss some. JS still isn't the fastest thing in the world and of course if there would be a built-in option in browsers, that would be awesome, I absolutely welcome it.
Hey, if you find a better implementation, I'll be happy to see. Good luck ;)
The other article and example is great! It's from a different perspective - user wants to hold causing an emotional state and the button and emotion working together, fantastic! The interactivity is the main point in all of those. Websites are still too static.