Components

Hotkey

A Stimulus controller that triggers click or focus on the element when a keyboard shortcut is pressed.


Installation

  1. Install the package

    Terminal
    $ yarn add @stimulus-components/hotkey
    
  2. Register the controller in your application

    app/javascript/controllers/index.js
    import { Application } from '@hotwired/stimulus'
    import Hotkey from '@stimulus-components/hotkey'
    
    const application = Application.start()
    application.register('hotkey', Hotkey)
    

This controller is based on Basecamp's fizzy hotkey controller.

Example

Hotkey

Press g to click the link.

Go to docs (g)

Press j to click the button

Press k to focus the text input.

Usage

Bind key events with Stimulus actions. The controller ignores key presses when the event target is inside an input or textarea.

Click on key (link):

app/views/index.html
<a href="/docs" data-controller="hotkey" data-action="keydown.g@document->hotkey#click"> Go to docs (g) </a>

Click on key (button):

app/views/index.html
<button type="button" data-controller="hotkey" data-action="keydown.j@document->hotkey#click">Submit</button>

Focus on key:

app/views/index.html
<input
  type="text"
  data-controller="hotkey"
  data-action="keydown.k@document->hotkey#focus"
  placeholder="Focus target (k)"
/>

Use any keyboard event filter in the action (e.g. keydown.space, keydown.esc).

The controller does not run when the event is defaultPrevented or when the element has pointer-events: none.

Extending Controller

You can use inheritance to extend the functionality of any Stimulus component:

app/javascript/controllers/hotkey_controller.js
import Hotkey from "@stimulus-components/hotkey"

export default class extends Hotkey {
  click(event) {
    super.click(event)
    console.log("Do what you want here.")
  }

  focus(event) {
    super.focus(event)
  }
}

This controller will automatically have access to targets defined in the parent class.

If you override the connect, disconnect or any other methods from the parent, you'll want to call super.method() to make sure the parent functionality is executed.