Search code examples
ruby-on-railsstimulusjs

Stimulus keyboard events don't appear to be working


According to the reference sheet for Stimulus actions, you can define keyboard event descriptors as described here

Thus I have a button that goes to the video_container controller:

%button{type: "Button", data: {action: "keydown.k->video-container#playPause",
 video: {container: {target: "playButton"}} Play

and in my controller:

playPause() {
  alert("This event is working")
}

I had this working for a click event with:

%button{type: "Button", data: {action: "click->video-container#playPause",
 video: {container: {target: "playButton"}} Play

But it doesn't work with the keydown or keyup events. I even added the :prevent option to call preventDefault() but that didn't work either.

Did I miss something?

EDIT UPDATE

Further tinkering here. I found that I could get the enter key event to do something:

%button{type: "Button", data: {action: "keydown.enter->video-container#playPause",
 video: {container: {target: "playButton"}} Play

But none of the others work. using space makes the document move downward.

I even tried their example of a compound modifier ctrl+a and that wasn't working either.


Solution

  • This will only likely work if you want to access the keypress while a user has focused on the button.

    <button type="button" data-action="keydown.k->video-container#playPause">play</button>
    

    This will create an event listener on the button only, and that event listener will trigger the method playPause only if the keydown event is fired and the letter k is pressed.

    <button type="button" data-action="keydown.k@document->video-container#playPause">play</button>
    

    This will add an event listener to document, remember that keypress events bubble. The event listener will trigger for any keyup anywhere in the DOM, irrespective of whether the button is focused. That listener will trigger the playPause method on that specific button's attached controller though.

    While this may seem a bit counterintuitive, it's actually really powerful and gives you lots of control over behaviour.

    A key take home is that data-action is basically equivalent to addEventListener on the element that has the data attribute. Some events bubble up from their target, some do not. But events can never bubble down to part of the DOM tree, so if you want events that are not inside the element with data-action you need to listen at the document or window (aka global event listeners).

    https://stimulus.hotwired.dev/reference/actions#global-events