This generalizes #397 to cover comments and PRs as well and provides the foundation to add other shortcuts in the future.
Shortcut#
For Linux/Windows: ctrl+enter
For macOS: cmd+enter
Proposed Behavior#
When creating/editing an issue/PR the shortcut can be used to submit the form, regardless of which of the inputs (title, body, etc.) is focused.
The same applies for comments—when the textarea of a comment is focused, it is submitted.
For the shortcut, the same rules as for the submit button apply—i.e. one cannot submit a comment through the shortcut if the textarea is empty.
Proposed Implementation#
A module shortcuts.js, which exports registerShortcuts and a focus helper.
registerShortcuts registers the provided shortcuts and returns a shared EventTarget for attaching listeners.
Registering Shortcuts#
Shortcuts would be registered like this:
import {registerShortcuts} from '/static/shortcuts.js';
registerShortcuts(['$mod+Enter']).addEventListener('$mod+Enter', handler);
With multiple shortcuts like this:
import {registerShortcuts} from '/static/shortcuts.js';
const shortcuts = registerShortcuts(['$mod+Enter', 'Escape']);
shortcuts.addEventListener('$mod+Enter', handleSubmit);
shortcuts.addEventListener('Escape', handleCancel);
Internally, the shortcuts are deduplicated, so there is only ever one listener on window.
Focus helpers#
Since we'll often need to check what is currently focused to decide if the handler should run,
we can also export a helper which checks if the activeElement (i.e. focused element) matches a selector.
Together it could look like this:
import {registerShortcuts, isFocused} from '/static/shortcuts.js';
registerShortcuts(['$mod+Enter']).addEventListener('$mod+Enter', () => {
if(isFocused('#issue-form #title, #issue-form #body')) {
// submit form
}
});
Alternative approaches considered#
I also explored scoped element-level shortcuts, where a
data-shortcuts='["$mod+Enter"]' attribute could be defined on the form element.
In this approach the events were dispatched directly on the closest [data-shortcuts] ancestor of the focused element.
This was intended to simplify event handlers, but ultimately didn't provide much benefit.
The element boundary of a whole form was too coarse—buttons inside the form would also match, so it was still necessary to
check focus explicitly, making the boilerplate roughly the same as the proposed approach.
Dependencies#
Here we can either use a library like tinykeys or a custom implementation.
Since tinykeys is just ~650 B, I feel like it is small enough, and it handles cross-platform modifier
keys and edge cases that are easy to get wrong in a custom implementation.
Also, this will enable us to add other shortcuts easily in the future.
Happy to hear your thoughts and feedback!
for most forms, we can just slap on this attribute:
and it will trigger the submit action.