vuejs: @keyup.esc on div element is not working

vue v on keyup enter not working
vue on esc click
vue keyup
vue keyup tab not working
vue click inline function
vue v-on:input
vue keypress
vue keyboard

I'm expecting that 'close' event is fired when I'm clicking ESC button being on "shadow-modal" div, but it's not happening

vue 2.5.13, any ideas why?

    <template>
      <div class="shadow-modal"
         @keyup.esc="$emit('close')">
        <transition name="modal">
          <div class="modal-mask">
            <div class="modal-wrapper">
              <div class="modal-container">
                <div class="modal-header">
                  <slot name="header">
                    default header
                  </slot>
                </div>
                <div class="modal-body">
                  <slot name="body">
                    default body
                  </slot>
                </div>
                <div class="modal-footer">
                  <slot name="footer">
                    <a href="#"
                       class="btn btn--diagonal btn--blue"
                       @click="$emit('close')">Cancel</a>
                  </slot>
                </div>
              </div>
            </div>
          </div>
        </transition>
      </div>
    </template>

While it's not input element that you're trying to bind the keyborad events, they will not work unless you define a tabindex:

<div class="shadow-modal" @keyup.esc="$emit('close')" tabindex="0">

Here's a reference: https://www.w3.org/WAI/GL/WCAG20/WD-WCAG20-TECHS/SCR29.html

Close a modal with the escape key, I'm expecting that 'close' event is fired when I'm clicking ESC button being on "​shadow-modal" div, but it's not happening vue 2.5.13, any ideas why? Buttons don't have keyup event on them. Even when you have focus on the button, and hit enter, it will be considered a click event, instead of keyup.enter.. Try binding the event to an input and it'd work.

(Apart from the 2 earlier answers.)

You don't have handle all event with Vue.

Here another way

export default {
  created() {
    document.onkeydown = evt => {
      evt = evt || window.event;
      if (evt.keyCode == 27) {
        this.$emit("close");
      }
    };
  }
};

Vue.js listen for Key Events on div, It's been a while that I search on the net a Vue.js directive that would allow me I tried full of directive like @ keyup.esc =" closeModalLogin " , @ keydown.esc =" closeModalLogin " etc . elements (inputs, buttons etc), if you add a tabindex to the modal div, you @tykus I'm sitting with the same problem. Teams. Q&A for Work. Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information.

While DmitrySemenov solution works for me it's not the best solution when you have multiple modals on the page. I tried it and I discovered it fires close event for every modal.

I think the best way to do it is registering a "keyup" event when the modal is shown and deregistering it after hide. It gives you an advantage because the event is registered only when it's needed. To do it you need to add a watcher for "show" property:

  props: {
    show: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    show() {   
      if (this.show === false) {
        window.removeEventListener("keyup", this.onEscapeKeyUp);
      } else {
        window.addEventListener("keyup", this.onEscapeKeyUp);
      }
    }
  },
  methods: {
    onEscapeKeyUp(event) {
      if (event.which === 27) {
        this.$emit("close");
      }
    }
  }

The modal should have v-if="show" that controls modal's visibility:

<div class="modal-mask" v-if="show" @click="$emit('close');">
Whole solution code (you can see it on codesandbox.io):
Modal.vue
<template>
  <transition name="modal">
    <div class="modal-mask" v-if="show" @click="$emit('close');">
      <div class="modal-wrapper" @click.stop>
        <div class="modal-container">
          <div class="modal-header"><slot name="header"></slot></div>
          <div class="modal-body"><slot name="body"></slot></div>
          <div class="modal-footer">
            <slot name="footer">
              <div class="buttons">
                <a class="button" href="#" @click.prevent="$emit('close');">
                  OK
                </a>
              </div>
            </slot>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
export default {
  name: "Modal",
  props: {
    show: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    show() {
      const body = document.querySelector("body");

      if (this.show === false && body.style.overflow === "hidden") {
        body.style.overflow = "";
        window.removeEventListener("keyup", this.onEscapeKeyUp);
      } else {
        body.style.overflow = "hidden";
        window.addEventListener("keyup", this.onEscapeKeyUp);
      }
    }
  },
  methods: {
    onEscapeKeyUp(event) {
      if (event.which === 27) {
        console.log("close event");
        this.$emit("close");
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.modal-mask {
  position: fixed;
  z-index: 1100;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  overflow: auto;
  transition: opacity 0.3s ease;
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal-wrapper {
  max-width: 980px;
  width: 100%;
}

.modal-container {
  padding: 1.5em 2em;
  background-color: white;
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
  transition: all 0.3s ease;
}

.wrapper {
  max-width: 980px;
}

.modal-body {
  margin: 1em 0;
}

.modal-enter {
  opacity: 0;
}

.modal-leave-active {
  opacity: 0;
}

.modal-enter .modal-container,
.modal-leave-active .modal-container {
  -webkit-transform: scale(1.1);
  transform: scale(1.1);
}
</style>
App.vue
<template>
  <div id="app">
    <button @click="show1 = true;">Show first modal</button>
    <button @click="show2 = true;">Show second modal</button>

    <Modal :show="show1" @close="show1 = false;">
      <div slot="header"><h1>First Modal</h1></div>
      <div slot="body">
        Lorem ipsum dolor sit amet consectetur, adipisicing elit. Rem beatae
        repellat dolores deleniti illum voluptatem facilis neque ut placeat,
        eius iusto tempore! Totam omnis non tempore perferendis expedita numquam
        neque!
      </div>
    </Modal>

    <Modal :show="show2" @close="show2 = false;">
      <div slot="header"><h1>Second Modal</h1></div>
      <div slot="body">
        Lorem ipsum dolor sit amet consectetur, adipisicing elit. Rem beatae
        repellat dolores deleniti illum voluptatem facilis neque ut placeat,
        eius iusto tempore! Totam omnis non tempore perferendis expedita numquam
        neque!
      </div>
    </Modal>
  </div>
</template>

<script>
import Modal from "./components/Modal";

export default {
  name: "App",
  components: {
    Modal
  },
  data() {
    return {
      show1: false,
      show2: false
    };
  }
};
</script>

@keyup.esc="hideModal" not working? · Issue #2 · maoberlehner , Something like <div @keyup.space="method()"> </div> exactly but I would assume it would work exactly like using it on input. div is not focusable element by default, you can make it focusable by  Ctrl + Click --> < div v-on:click.ctrl = "doSomething" > Do something </ div > Note that modifier keys are different from regular keys and when used with keyup events, they have to be pressed when the event is emitted. In other words, keyup.ctrl will only trigger if you release a key while holding down ctrl. It won’t trigger if you release

If you need to close a modal window, you must observe several conditions.

  1. In the tag of the modal window:
<div class="modal-content" ref="modal" tabindex="0" @keyup.esc="$emit('close')">
  1. In the lifecycle hook mounted():
mounted() {
   this.$refs.modal.focus()
}

Event Handling, An issue I'm encountering: the esc keyup event only seems to be triggered when added to an input field and not when added to a normal div, This isn't only related to your Modal but seems to be the case for the entirety of Vue. Do you  Slots. This page assumes you’ve already read the Components Basics. Read that first if you are new to components. In 2.6.0, we introduced a new unified syntax (the v-slot directive) for named and scoped slots. It replaces the slot and slot-scope attributes, which are now deprecated, but have not been removed and are still documented here.

My Alternative Implementation

<template>
  <div class="shadow-modal"
     @keyup.esc="$emit('close')">
    <transition name="modal">
      <div class="modal-mask">
        <div class="modal-wrapper">
          <div class="modal-container">
            <div class="modal-header">
              <slot name="header">
                default header
              </slot>
            </div>
            <div class="modal-body">
              <slot name="body">
                default body
              </slot>
            </div>
            <div class="modal-footer">
              <slot name="footer">
                <a href="#"
                   class="btn btn--diagonal btn--blue"
                   @click="$emit('close')">Cancel</a>
              </slot>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  beforeMount() {
    window.addEventListener('keyup', this.onEscapeKeyUp);
  },
  beforeDestroy () {
    window.removeEventListener('keyup', this.onEscapeKeyUp)
  },
  methods: {
    onEscapeKeyUp (event) {
      if (event.which === 27) {
        this.$emit('close');
      }
    },
  },
};
</script>

Methods and Event Handling, To address this problem, Vue provides event modifiers for v-on . div> <!-- only trigger handler if event.target is the element itself --> <!-- i.e. not from a child element --> <div <input v-on:keyup.page-down="onPageDown"> A few keys ( .esc and all arrow keys) have inconsistent key values in IE9, so these built-in aliases  It does work as intended with v-if.. v-if vs. v-show. When a v-if block is toggled, Vue.js will have to perform a partial compilation/teardown process, because the template content inside v-if can also contain data bindings or child components.

Testing Key, Mouse and other DOM events, To address this problem, Vue.js provides two event modifiers for v-on : .prevent and .stop . div>. <!-- only trigger handler if event.target is the element itself -->. <!-- i.e. not from a child element --> <input v-on:keyup.13="submit"> enter; tab; delete (captures both “Delete” and, if the keyboard has it, “Backspace”); esc  Note that v-show doesn’t support the <template> element, nor does it work with v-else. v-if vs v-show v-if is “real” conditional rendering because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles.

1. Vue.js: The Basics - Vue.js: Up and Running [Book], callMe('no') } } } </script>. Test. import YesNoComponent from '@/components/​YesNoComponent' import { mount } from '@vue/test-utils' import sinon from 'sinon'​  When working with non-mutating methods, you can replace the old array with the new one: example1.items = example1.items.filter( function ( item ) { return item.message.match( /Foo/ ) }) You might think this will cause Vue to throw away the existing DOM and re-render the entire list - luckily, that is not the case.

vuejs: @keyup.esc on div element is not working. I'm expecting that 'close' event is fired when I'm clicking ESC button being on "shadow-modal" div, but it's not  Note: If there is no <slot></slot> element in the child's template, any content from the parent will be silently discarded. Fallback Content. If the parent does not inject any content into the child’s slot, the child will render any elements inside its <slot></slot> tag, like so: ChildComponent.vue

Comments
  • Tried, it works only if I click on the "DIV" first, then ESC closes the panel. If modal opened and then immediately you click ESC - nothing happens.
  • @DmitrySemenov setting the event listener @keyup.esc on root div instead would work. Another way is to trigger focus on the "DIV" whenever modal opened.
  • Add in mounted to close without click on the DIV: this.$refs.modal.focus()
  • This is not necessary, and will pick up ALL keydown events.
  • codesandbox.io/s/038lv1n1vl As mentioned in another answer, you can use tabindex