Craig
Craig

Reputation: 8294

Differentiate between mouse and keyboard triggering onclick

I need to find a way to determine if a link has been activated via a mouse click or a keypress.

<a href="" onclick="submitData(event, '2011-07-04')">Save</a>

The idea is that if they are using a mouse to hit the link then they can keep using the mouse to choose what they do next. But if they tabbing around the page and they tab to the Save link, then I'll open then next line for editing (the page is like a spreadsheet with each line becoming editable using ajax).

I thought the event parameter could be queried for which mouse button is pressed, but when no button is pressed the answer is 0 and that's the same as the left mouse button. They I thought I could get the keyCode from the event but that is coming back as undefined so I'm assuming a mouse event doesn't include that info.

function submitData(event, id)
{
    alert("key = "+event.keyCode + "  mouse button = "+event.button);
}

always returns "key = undefined mouse button = 0"

Can you help?

Upvotes: 39

Views: 26175

Answers (9)

user17269164
user17269164

Reputation: 31

Nowadays, you can make use of instanceof which even has full browser support.

function onMouseOrKeyboardSubmit(event, id) {
    if (event instanceof KeyboardEvent) {
        alert("Submitted via keyboard");
    } else if (event instanceof MouseEvent) {
        alert("Submitted via mouse");
    } else {
        alert("Unexpected submit event");
    }
}

Upvotes: 3

Craig Kovatch
Craig Kovatch

Reputation: 382

I use the following

const isKeyboardClick = nativeEvent.detail === 0 && !nativeEvent.pointerType;

Works in evergreen browsers via detail and IE11 via pointerType. Does not work for the case where e.g. radio button <input> is wrapped by a <label> element.

Upvotes: 3

dzuc
dzuc

Reputation: 760

Wasn't able to come up with solution relying entirely on the events but you can position an anchor tag over a button and give it a tabindex of -1. This gives you a button that can be focused and engaged with keyboard enter/spacebar, as well as giving you a clickable surface that gives you an option to differentiate the two codepaths.

.button {
  position: relative;
}

.anchor {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
<button id="button" class="button">
  button
  <a class="anchor" href="#example" tabindex="-1"></a>
</button>

Upvotes: 1

C&#233;lia
C&#233;lia

Reputation: 359

I know this is an old question but given how much time I lost looking for a working, no jquery and IE-compatible solution, I think it won't be a bad idea to put it here (where I came first).

I tested this and found it working fine :

let mouseDown = false;

element.addEventListener('mousedown', () => {
  mouseDown = true;
});

element.addEventListener('mouseup', () => {
  mouseDown = false;
});

element.addEventListener('focus', (event) => {
  if (mouseDown) {
    // keyboard
  } else {
    // mouse
  }
});

Source link : https://www.darrenlester.com/blog/focus-only-on-tab

Upvotes: 1

Yvain
Yvain

Reputation: 952

You can use event.detail

if(event.detail === 0) {
    // keypress
} else {
    // mouse event
}

Upvotes: 15

Wernight
Wernight

Reputation: 37600

Could check if event.screenX and event.screenY are zero.

$('a#foo').click(function(evt) {
  if (evt.screenX == 0 && evt.screenY == 0) {
    window.alert('Keyboard click.');
  } else {
    window.alert('Mouse click.');
  }
});

Demo on CodePen

I couldn't find a guarantee that it works in all browsers and all cases, but it has the benefit of not trying to detect a "click" done via the keyboard. So this solution detects "click" more reliably at the cost of detecting if it's from keyboard or mouse somewhat less reliably. If you prefer the reverse, look as the answer from @Gonzalo.

Note: One place I found using this method is Chromium

Upvotes: 24

SeanCannon
SeanCannon

Reputation: 77956

You can create a condition with event.type

function submitData(event, id)
{
    if(event.type == 'mousedown')
    {
        // do something
        return;
    }
    if(event.type == 'keypress')
    {
        // do something else
        return;
    }
}

Note: You'll need to attach an event which supports both event types. With JQuery it would look something like $('a.save').bind('mousedown keypress', submitData(event, this));

The inline onClick="" will not help you as it will always pass that click event since that's how it's trapped.

EDIT: Here's a working demo to prove my case with native JavaScript: http://jsfiddle.net/AlienWebguy/HPEjt/

I used a button so it'd be easier to see the node highlighted during a tab focus, but it will work the same with any node.

Upvotes: 13

Gonzalo Larralde
Gonzalo Larralde

Reputation: 3541

You can differentiate between a click and a keyboard hit capturing and discarding the keydown event originated at the moment of the key press:

jQuery(function($) {
    $("a#foo").keydown(function() {
        alert("keyboard");
        return false;
    }).click(function() {
        alert("mouse");
        return false;
    })
})

http://jsfiddle.net/NuP2g/

Upvotes: 5

SLaks
SLaks

Reputation: 887195

Handle the mouseup event.
If you get a click right afterwards, it was probably done with the mouse.

Upvotes: -2

Related Questions