I felt pretty strongly that I would hate triggering events on mouseDown because of how often I "cancel" an action mid-click. But I decided to add this userscript to my browser and live with it for a week:
let preventNextClick = false;
const interactiveElements = ['a', 'button', 'input', 'select', 'textarea'];
document.addEventListener('mousedown', (event) => {
if (event.metaKey) return; // allow cmd+click to bail
if (event.button !== 0) return; // handle left clicks only
// ignore all but a handful of elements
const tagName = event.target.tagName.toLowerCase();
if (!interactiveElements.includes(tagName)) return;
event.target.click();
// set a flag to prevent firing two click events
preventNextClick = true;
});
document.addEventListener('click', (event) => {
if (preventNextClick) {
event.stopImmediatePropagation();
event.preventDefault();
preventNextClick = false;
}
}, true); // use capture phase
This causes any of the interactive elements on a page to trigger their onClick action during the mouseDown phase rather than onMouseUp. It's probably not perfect, just a scrappy user script. But omg it is so much nicer to browse with this enabled. And I say that as a hater of the original idea with strong opinions.So, if you want to have a slightly more informed opinion on the issue I suggest trying this or something like it out for a week! I can't go back to the way it was before. Everything is so snappy now.
I haven't (yet) found a case where I wished I had the mid-click cancelability I had before. I think that getting used to the idea of clicks being instant rewired my brain a bit to simply not rely on that behavior anymore.
- Browsing HN, and your scroll gesture happens to start where a link is? Before you know it, you’ve navigated away.
- Long pressing to delete an app, and the app opens in the meantime? Awkward UX.
In the majority of cases, press gestures are competing with other gestures like scrolling. Waiting until you’ve released is often the first moment that it’s 100% clear which gesture you intended. If both gestures get invoked, it will probably lead to much worse problems.
I’m sure there are cases where act on press makes sense, but I don’t think it’s as dramatic as the tweet makes out.
In almost all games I play there is an inventory and a hotbar and the way you assign items to the hotbar is by dragging it. To use the item from the inventory you release the button without dragging. How else could this be done?
I am not at all surprised to know that Android had some questionable default behaviors.
- most elements are ON RELEASE
- except the phone number entry or passcode entry, these are ON PRESS
- but the "backspace" button is ON RELEASE
I'm guessing because there are so many other interactive options on iOS (touch hold, hold drag, 3d press, swipe) this proposed paradigm is less likely to have much impact.
I think the reason why UI designers move away from this is because on touch devices, touches have a double meaning, a short and long tap do different things, so you have to act on release.
> it reduces user errors
Act on press significantly increases user error because in most cases, it is not the norm, so when it shows up, users take actions they didn't mean to. I can't stand it when a button is act on press.
> and it is good UI design to favor them when possible
Saving tens of milliseconds in a button press does not automatically correlate to good UI design. Saving time is the only justification he gave, which is what you'd expect out of a graphics engine programmer. And he just suggested before this line that it would be good to have mixed behaviors, which makes no sense.
well thats one way to demonstrate a misunderstanding of many UI
Sliding out is also exactly how you cancel events we when you realize you've made a mistake by clicking on autopilot.
Though hard to say definitively which one is better without more explicit comparison of these two styles of interactions
For non critical actions where there is an easy undo - yes go ahead, e.g. in his example for an on-screen keyboard it makes sense. If you make a mistake you can easily undo it. But not when it comes to completing a major transaction.
Lot's of places, I want faster response (the controls in computer games, yes, of course!) but NOT in interface elements, there I want the response on release, so I have the extra opportunity to realize my fuckup and amend the situation.
This technique hides about 80 ms of latency when triggered on mousedown and up to a few hundred milliseconds for hover.
Even if I disagree with the concept in general, unless you have very simple and pervasive undo, perhaps.
A less militant solution might be highlight-on-press. We can at least ensure the UI is as visibly responsive as possible even if actions need to wait for gestures to complete.
It cheats your brain by loading the new page once link is pressed (or even hover). Not on release.
While we're talking about how things could be better, though, long static hold on a draggable item on touch devices should natively cause dragstart.
The whole point of having a release event is another UX usability principle: being able to undo a click or tap.
Having disabled players conducting real UAT to ensure UX is appropriate for a wide audience is also important.
Cancelling an event after down press is really good outside of games.
In games holding a button down for a little or a lot longer is a good stand-in for “pushing hard” which you want the game to react to.
- Sometimes the content can be scrolled, so it’s not clear when the user presses whether they intend to scroll or actually press the button. Similarly, sometimes the pressed item can also be dragged.
- Other times the buttons may be small and the user may have fat-fingered, so it’s important they can drag outside the button to cancel (or in some cases, like the keyboard, maybe select a different button).
- Some buttons have special “long press” or “hard press” actions, particularly on iOS. This is really good UI, and it only works if the button’s normal trigger occurs on release or the normal trigger segues into the long-press trigger.
- Even when none of the above apply, the user is still conditioned to expect the button will trigger on release. They aren’t going to deduce “this button isn’t in a scrollable area and is large enough and has no long-press action (or the normal action segues into the long-press action), so it will trigger instantly”.
- It almost never makes a difference to wait for the user to release. If the content loads fast enough, it will load before their brains’s reaction time (they are releasing the button before their brain can start processing new content). If you really care, to remove 0.1 seconds of latency, you can preload the content when the user taps the button, commit it on normal release, and revert it on cancel. Toggle and selector buttons have no immediate effect, so for them it never makes a difference.
On desktops it matters less whether buttons trigger on press or release, but IMO it still matters. “Long-click” isn’t common and scrolling is done differently, but there are still draggable elements, “fat-fingering”, and conventions. The thing that matters, for both desktop and mobile, is that the button or item has a “(being) pressed” state that looks different than the selected state. IMO if the button doesn’t have a pressed state, it feels more natural for it to trigger on press; but it feels more natural for the button to have a pressed state than not, and when it does have this state, it feels more natural for it to trigger on release.
UI elements that the user “taps and scrolls” (minus the text cursor) like sliders and color pickers are typically expected to react instantly to the user’s touch (and a slider or color picker in a scrollable view is bad UI, because it interferes with this). Although even these elements I’d prefer go into a “pressed” state, to indicate that if the user releases or scrolls within the control it will switch to the value at their finger, but if the user cancels (e.g. simultaneously presses somewhere else with another finger, or scrolls vertically outside of a slider) it will keep its original value.
The one place instant-trigger buttons are important is real-time game UI, where reaction time is important, hence the author’s observation. Although instant triggers don’t matter in out-of-game UI, there are reasons why they may carry over: said UI may be written in the same framework, with the same developers, or the studio may wants to make the entire game’s UI responsiveness consistent. Non-real-time games may also benefit from instant-trigger buttons, although I’m less sure of their importance in these games, it seems they are common. Perhaps a game like Shattered Pixel Dungeon would feel “delayed” if it didn’t have instant triggers, especially if you are playing it really fast, even though AFAIK time in that game is entirely determined by your sequence of inputs.
From time to time I encounter web systems that get this wrong, using keyup or keypress instead of keydown, or using mousedown instead of click¹. Most people won’t notice, I expect, but I suspect I pretty much always immediately notice and find them infuriating, because they break the universal convention—things that you’re used to being able to do, don’t work as you expect. Perhaps my favourite example of this was some system which would close some form when you released Escape—so when I had something else open above the browser at the OS level (or maybe it was even just a <select> dropdown! Actually that sounds right; I know I triggered this too often) and closed it by pressing Escape, the web page underneath then received the keyup, and so the Escape press closed two things in one go, which was never what I wanted.
If you can start executing an action on mousedown and only commit it functionally and visually once it turns into a click, go ahead. But otherwise, please don’t act on press, because it’s wrong.
The on-screen keyboard he mentions… well, I’m actually a bit puzzled by that, because it should completely obviously map press to keyboard press, and release to keyboard release, and anything else would be wrong, so how was there ever an argument, and in fact how else could you implement it? I genuinely don’t see any alternative, if you’re working on an OS that has the concept of keyboards already. Ultimately, I don’t think it supports his point at all, because he was implementing a keyboard.
—⁂—
¹ Note that even monitoring mousedown + mouseup may sometimes be wrong, due to nuances that can cancel the click mid-press; things being draggable is the obvious example, but I think some platforms let you hit Escape on a keyboard, or maybe have other multi-pointer quirks.
Most micro-processors has useful edge- and level-detect interrupt features that allows instant unconditional jump to interrupt handling subroutine(think callback functions) often used for physical buttons handling.
And one of common knowledge associated with that is, physical buttons tend to go through a transitional random state while being pressed, generating rapid succession of false on-off signals. This could trigger the interrupt detection feature, and while there will be little chances of memory leaks and no GC mess from this at all thanks to interrupt systems being static objects, it could still put system in a weird state and/or massively slow it down.
The most typical solution to button chattering problem is as follows:
1. have the button input pin triggered for rising edge(button not pressed to pressed).
2. upon detection, immediately disable interrupt upon trigger, optionally send button down event to OS.
3. wait a millisecond, or for whatever duration the button takes to settle.
4. while at it, re-trigger the interrupt now for falling edge to detect button release.
5. on falling edge, pass the button up and button click events to the OS, or call the onClick() callback, and configure everything back to 1.
(0. call the hardware guy cubicle for further discussions)
... which results in classic MacOS style behavior of button press greying the button without action, and that is cute.But the point is, it's less of a UX feature, more of hardware quirk suppression. Certainly a VR keyboard button virtually pressed by 3D spatial location of individual fingers don't require such pieces of anti-chattering code.
[expletive], I'm bad at drawing conclusions. Maybe I could say, by Chesterton's Fence principle, here the theory of Act on Release implementation is explained, and removal of fence can now be freely discussed.
> it reduces user errors by not allowing the focus to slide out of the hot box between press and release
No, it increases user errors by not allowing the focus to slide out of the hot box between press and release.
Yeah, in FPS or other games where reaction time matters, or just games in general, you always want to act on press.
In all other apps, act on release.
------
Act on press
This is a UI design hill I will die on, and it dismays me how often and hard I have had to fight for it.
Almost all interaction methods have a “press” and “release” event associated with them. Whenever possible, you should “do the thing” when you get the press event instead of waiting for the release event, because it makes the interaction feel substantially more responsive, and it reduces user errors by not allowing the focus to slide out of the hot box between press and release.
Even a “ballistic tap”, where your finger is intentionally bouncing off the button or touch surface, involves several tens of milliseconds delay between the press and release, and most button presses have well over a hundred ms dwell time. There is a delight in interfaces that feel like they respond instantly to your wishes, and the benefit to every single user is often more important than additional niche features.
Game developers, with simple UI toolkits, tend to get this right more often, but “sophisticated” app designers will often fight hard against it because it is mostly incompatible with options like interactive touch scrolling views, long press menus, and drag and drop.
Being able to drag scroll a web page or view with interactive controls in it is here to stay, and nets out way better than having to use a separate scroll bar, but there are still tons of fixed position controls that should act on press, and it is good UI design to favor them when possible.
In the early days of mobile VR, the system keyboard was a dedicated little OpenGL app that responded instantly. With full internationalization it became prudent to turn it into a conventional Android app, but the default act-on-release button behavior made it feel noticeably crappier. The design team resisted a push to change it, and insisted on commissioning a user study, which is a corporate politics ploy to bury something. I was irritated at how they tried to use leading questions and tasks, but It still came back one of the clearest slam-dunks I have seen for user testing – objectively less typos, expressed preference, and interview comments about the act-on-press version feeling “crisper” and “more responsive”.
So, I won that one, but the remaining times I brought it up for other interfaces, I did not, and you still see act-on-release throughout the Meta VR system interfaces.
For many others, though, I like to be able to press, move whatever pointing device I'm using from the hot zone, and release to cancel the action. It's like holding the chess piece.