Skip to content

Blog

Add Keyboard Shortcuts to your Vue App ⌨️

09.01.2020 | Tutorial Frontend | James McMahon
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>

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";
      }
    }
  }
});

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";
    }
  }
}

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();
  });
});

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

Share