DEV Community

Cover image for Add Keyboard Shortcuts to your Vue App ⌨️
James McMahon for Focused

Posted on • Updated on • Originally published at focusedlabs.io

Add Keyboard Shortcuts to your Vue App ⌨️

I recently had to add some support for global key shortcuts in a Vue application I am working on. Vue has built-in support for listening to keys when you are in an input element. What is not supported directly are global shortcuts. For instance, if I am viewing an email in Gmail, I can hit 'a' to answer that email.

To accomplish this in Vue with either need to use low-level JavaScript event listeners or a plugin, like vue-shortkey. The approaches are not actually that different since vue-shortkey is, not surprisingly, just wrapping event listeners. It is straight forward to write your own event listener in a component so I didn't see a huge amount of value in using a plugin. There are a few blog posts covering event listeners in Vue already, but I am going to take a stab a showing a more complete example here, including how to test the component.

Implementing

Let's say we wanted to create a component that displays a message whenever the escape key is pressed.

Our Template block:

<div>{{ message }}</div>
Enter fullscreen mode Exit fullscreen mode

Our Script block (Typescript):

import Vue from "vue";

export default Vue.component("Demo", {
  created() {
    window.addEventListener("keydown", this.escapeListener);
  },
  // make sure you remove the listener when the component is no longer visible
  destroyed() {
    window.removeEventListener("keydown", this.escapeListener);
  },
  data: function() {
    return {
      message: ""
    };
  },
  methods: {
    escapeListener(event: KeyboardEvent) {
      if (event.key === "Escape") {
        this.message = "Escape has been pressed";
      }
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

If you prefer to use class syntax, change the script block to the following:

export default class Demo extends Vue {
  private message = "";

  private created() {
    window.addEventListener("keydown", this.escapeListener);
  }

  private destroyed() {
    window.removeEventListener("keydown", this.escapeListener);
  }

  private escapeListener(event: KeyboardEvent) {
    if (event.key === "Escape") {
      this.message = "Escape has been pressed";
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Testing

This is all well and good, but it was not immediately clear how you test this behavior. After a few false starts, I stumbled upon a Github issue thread with the solution.

The magic I was missing was to use the Vue testing utils attachToDocument option when mounting or shallow mounting the component under test. Once we attach our component to a document, we can use wrapper.trigger to simulate our keypresses.

describe("Demo.vue", function() {
  it("Displays a message when escape is pressed", function() {
    const wrapper = shallowMount(Demo, { attachToDocument: true });

    // the browser will add 'key' to the event,
    // but when testing we need to add it manually
    wrapper.trigger("keydown.esc", { key: "Escape" });

    expect(wrapper.text()).to.include("Escape has been pressed");

    // always make sure to destroy when using attachToDocument
    wrapper.destroy();
  });
});
Enter fullscreen mode Exit fullscreen mode

And that is it, a straightforward way to test-drive our global shortcuts as we add them to our component.

Top comments (2)

Collapse
 
ifgr profile image
Fagner Araujo

First of all, great article and thanks to quote vue-shortkey.

The main reason to not use your approach is the fact you will attach so much listeners in your application and it is not good. Think about change the page and the effort to control the dismisses.

Vue-Shotkey use only one listener globaly! And dispatch the action only when is needed.

Collapse
 
dakujem profile image
Andrej Rypo

For simple stuff at least, this works well.