4

I'm working on keyboard shortcuts for a web application and need to check if a keypress should trigger the shortcut or if it is just the user typing and should therefore not trigger the shortcut.

For example, a common pattern is to use the / or s keys to open the global search bar. Obviously this should not open the search bar if the user is typing into another input.

The ideal logic would go something like this: On keypress, check the currently focused element. If the element accepts keyboard input (can be typed into), then do nothing. If the element does not accept keyboard input, run the shortcut.

Note that checking for focusability is not enough because links and buttons are focusable, but do not accept keyboard input (in the way I mean here).

Here's what I have so far:

function acceptsKeyboardInput(element) {
    return (
        element.tagName === "INPUT" ||
        element.tagName === "TEXTAREA" ||
        element.isContentEditable
    );
}

Does this approach catch every case or is there a better way to tell if an HTML element accepts keyboard input?

Henry Woody
  • 11,997
  • 7
  • 34
  • 47
  • It seems like a good non verbose check tough, why are you looking for an alternative solution, is it not working as intended ? – Cesare Polonara May 15 '22 at 20:01
  • Basically, any element that is focus-able should be able to receive keyboard input. You can read the official docs about that here: [Keyboard - Accessibility](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Keyboard). You can have a look at [this question](https://stackoverflow.com/questions/18261595/how-to-check-if-a-dom-element-is-focusable) on how to detect if an element is focus-able or not. – icecub May 15 '22 at 20:02
  • @CesarePolonara I wrote that code while writing this question, so I may have figured it out. But now just want to check if there is either a built-in API for doing this (or more direct way) or if there is a case I am missing. – Henry Woody May 15 '22 at 20:04
  • @icecub I made a small update to the question, but focusability isn't what I'm after here as links and buttons are focusable but you can't type into them. – Henry Woody May 15 '22 at 20:05
  • @icecub but you can make an element focusable by setting the `tabindex` attribute, so that could make an element focusable but not editable. – Cesare Polonara May 15 '22 at 20:07
  • I believe only form elements have the `readOnly` attribute. I know that doesn't answer your question but maybe it can help – Spencer May May 15 '22 at 20:08
  • According to how JQuery has implemented [focusable](https://github.com/jquery/jquery-ui/blob/70dae67b73dfea9126f126f516fe8286f1e73417/ui/focusable.js), it looks like there isn't any straightforward way to check whether an element can receive inputs. But chances are that your solution already covers all your needs – Cristian Traìna May 15 '22 at 20:10
  • @Henry I see, I think you should use `Document.activeElement` to check the current focused element on `window.onkeydown` and perform the check you exposed, if it's not an input/textarea/contenteditable you're good to go. – Cesare Polonara May 15 '22 at 20:10
  • @CesarePolonara That's like saying that your car is running because you fired it up. If you specifically choose to make an element focus-able, you shouldn't complain that it is detected as focus-able. – icecub May 16 '22 at 07:37
  • @HenryWoody Afaik, there is no standard way to detect if an element accepts keyboard input as in "can be typed into". You'll probably have to make a list of standard elements and / or attributes that can be typed into and finally check for the global attribute `.isContentEditable;` for any other element that you've given the `contenteditable` attribute. – icecub May 16 '22 at 07:48

1 Answers1

0

Will all shortcuts be more than one key? If so you can listen for input and prevent a shortcut from running with a boolean value.

var is_input = false
window.addEventListener('keydown', function (e) {
    console.log(is_input)
    is_input = false
})
window.addEventListener('input', function (e) {
    is_input = e.constructor.name == 'InputEvent'
})

Expected output for /s while able to type would be true or false (depending on the previous is_input value) at / keypress then true at s keypress and all keys following.

Expected output for /s while not able to type would be true or false (depending on the previous is_input value) at / keypress then false at s keypress and all keys following

Spencer May
  • 3,993
  • 9
  • 27
  • 46
  • Note: this works for all inputs including content editable HTML. However, I did notice keydown isn't called when type searching in a standard `select` element – Spencer May May 15 '22 at 21:35