Search code examples
javascripthtmldom-events

HTML <video> tag - key events not received without controls attribute | Event#preventDefault not cancelling controls


I have attempted to display a video with custom controls. It seems to be working fine, but I have one problem. The controls attribute seem to be causing problems when I try to listen for key events.

I currently have this piece of code for testing:

const video = document.getElementById("video");

video.addEventListener("keypress", (event) => {
    console.log("keypress");
    console.log(`  Key: ${event.which}`);
    
    event.preventDefault();
});

I have done the same for keydown as well, but it has the same problem. The problem being one of two things:

  • If the <video> tag does not have the controls attribute: The event is never received, so the messages never get printed to the console.
  • If the <video> tag has the controls attribute: The event is received and the messages are printed to the console, but the event.preventDefault() call does not stop the behaviour caused by having the controls attribute, so I can still play/pause the video using space (it does stop me from using enter, for some reason), seek using the left/right arrow keys, and adjust the volume using the up/down arrow keys.

Q&A:

  • Q: Have you tried reacting to the event(s) not on the video element itself, but something like a wrapper div? Not sure if that makes a difference, but I’d figure it might be worth a try.
  • A: Yes. I did try that, but unfortunately, it only received the key events when the focus was on my custom control buttons.

I have attempted to find a solution for the past day, but to no avail. If you have any suggestions, please do let me know.


Solution

  • I finally got it working, after typing back and forth through the comments.

    Listening for the keydown event on the document in capture phase allows me to use event.preventDefault(). I just have to add some conditions so it does not cancel all key presses in the document.

    const video = document.getElementById("video");
    
    document.addEventListener("keydown", (event) => {
        if (event.target !== video) return;
        
        // Space has keyCode 32
        if (event.which === 32) event.preventDefault();
    }, true);