Detect single click events distinguished from click-and-drag or double-click-and-drag

Is there any way to distinguish a click event that keeps it distinct from when the user actually ends up dragging the mouse? I have some text that is filled with links, and want it to be easy for the user to click and drag over the text to select some of the text, but the links make this difficult, as the browser interprets it as them trying to drag the link, rather than select some text. So my solution to this problem was to use an <a onClick=...> rather than <a href>, as the browser lets me drag the mouse over that just like normal text.

However, this only seems to work if I single click and drag the mouse over two separate <a> tags: if the selection is entirely internal to an <a> tag the event still fires, and if I try to double-click-drag over text it also fires.

So I'm wondering if there's a way to do this other than using onMouseDown and onMouseUp and manually keeping track of the delays to determine what the user is doing.

I'm aware that some browsers offer the option to drag through links by holding a modifier key, but I'm curious if there's a simpler way to do this that wouldn't require users to be aware of that functionality.


Solution 1:

Opinion piece

Whilst this might be doable, consider accessibility and how it'll fit into your projects needs. Navigation using onclick doesn't provide the same accessibility benefits, plus it requires a lot of reinventing things the browser can do for free.

I know that mobile devices typically allow a long press to access a text-select/context menu combo; on desktop, it'll vary per device/browser.


Actual answer

The only "detect click only" implementation I can think of would be using three handlers with mousedown, mouseup and mousemove. Untested code ahead!

let clicked = false;
document.addEventListener('mousedown', e => { clicked = true; });
document.addEventListener('mousemove', e => { clicked = false; });
document.addEventListener('mouseup', e => { 
    if(clicked) {
        // The mouse was clicked without moving it around!
        // Do your "only clicked" logic in here.
    }

    // Reset this back to false for next time
    clicked = false; 
});