0

I want to bind some hotkeys to a div: Whenever the user clicks somewhere inside the div and then presses the S key I want to console.log something. However, I don't want this hotkey to be global and to be triggered each and every time the user presses S.

Here is what I've got so far:

import React from "react" import Mousetrap from "mousetrap" export default class Mouse extends React.Component { constructor(props) { super(props) } componentDidMount() { let form = document.querySelector("form") let m = new Mousetrap(form) m.bind("s", () => { console.log("s") }) } componentWillUnmount() { // m.unbind("s", () => { // console.log("s") // }) } render() { return ( <form style={{ width: "300px", height: "300px", backgroundColor: "pink" }} > <input type="text" /> </form> ) } } 

The Mousetrap docs say that I can bind my mousetrap like so:

var form = document.querySelector('form'); var mousetrap = new Mousetrap(form); mousetrap.bind('mod+s', _handleSave); mousetrap.bind('mod+z', _handleUndo); 

As you can see in my example above, that's what I've done. It does work in this sense: whenever I type S while I'm in the input of the form, the console.log is being triggered. However, I don't want to use a form and neither do I want my user to be inside an input: I just want my user to have clicked on the div. I cannot get this to work though. I would expect it to look something like this:

import React from "react" import Mousetrap from "mousetrap" export default class Mouse extends React.Component { constructor(props) { super(props) } componentDidMount() { let form = document.querySelector(".trigger") let m = new Mousetrap(form) m.bind("s", () => { console.log("s") }) } componentWillUnmount() { // m.unbind("s", () => { // console.log("s") // }) } render() { return ( <div className="trigger" style={{ width: "300px", height: "300px", backgroundColor: "pink" }} > Click me! </div> ) } } 

However, this doesn't work. Nothing is being triggered.

Edit: Also, one thing I don't quite understand in the first example above is that I am binding Mousetrap to form. However, the s hotkey is only ever triggered when I am inside the input field of form, but never when I just click on the form but not the input.

2
  • What exactly do you mean with Whenever the user clicks somewhere inside the div and then presses the S key. Do you want the click to be registered while the cursor is inside the div or does does the user really have to click first? Also should subsequent presses of S also be registered or does the user have to click the div again? Commented Dec 4, 2019 at 13:47
  • I'm sorry, I think I was unclear. I would like the user to click the div, then I highlight the border or something to show that the element is active. an while that element is active, the hotkeys should work. So there is no need to click again. I don't want hovering or anything like this to do anything. Thanks again for asking :) Commented Dec 4, 2019 at 13:50

2 Answers 2

2

The reason this happens is that the Mousetrap is checking if the element is focused. divs (or in fact any other block element like a form) can only be focused if they have a tabindex defined. Inputs can be focused without that.

But I believe you do not need to explicitly bind the Mousetrap to the div at all. All you need to do is to track the active state of your div and bind() or unbind() the trap accordingly.

Example:

class Mouse extends Component { state = { active: false, } constructor(props) { super(props); this.trap = new Mousetrap(); } handleClick = () => { this.setState(({active}) => { if (!active) { this.trap.bind('s', this.handleKeyPress); } else { this.trap.unbind('s'); } return {active: !active} }) } handleKeyPress = () => { console.log('User pressed S.') } componentWillUnmount() { this.trap.reset(); } render() { const {active} = this.state; return ( <div className={cN('trigger', {active})} onClick={this.handleClick} > Click me! </div> ); } } 

Demo:

Edit modest-edison-hdfp7

Sign up to request clarification or add additional context in comments.

1 Comment

thanks a lot. what's the advantage of doing it like this, as opposed to binding Mousetrap + tabindex? I feel the binding solution is a bit more concise and simpler overall? What do you think?
0

I think I've found the solution. Giving the div a tabindex makes it selectable, and thus, the hot key will be registered. I am not sure why this is, whether it's strictly necessary or a bit of a hacky solution. So all I had to do is:

<div className="trigger" tabindex="0"> 

...if anyone has a better explanation that goes in some more depth, feel free to post still, as I won't select this as the final answer for now.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.