diff --git a/src/components/Modals/AddModal.vue b/src/components/Modals/AddModal.vue
index 50ea4b98..d8683259 100644
--- a/src/components/Modals/AddModal.vue
+++ b/src/components/Modals/AddModal.vue
@@ -6,8 +6,7 @@
     max-width="500px"
     :fullscreen="phoneLayout"
     persistent
-    @keydown.enter.prevent="$refs.addTorrent.click"
-    @keydown.esc.prevent="close"
+    @keydown.enter.prevent="submit"
   >
     <div
       class="noselect"
@@ -124,7 +123,7 @@
         <v-spacer />
         <v-form>
           <v-card-actions class="justify-center">
-            <v-btn ref="addTorrent" text :disabled="!valid" class="accent white--text mx-0 mt-3" @click="submit"> Add Torrent </v-btn>
+            <v-btn text :disabled="!valid" class="accent white--text mx-0 mt-3" @click="submit"> Add Torrent </v-btn>
             <v-fab-transition v-if="phoneLayout">
               <v-btn color="red" dark absolute bottom right @click="close">
                 <v-icon>{{ mdiClose }}</v-icon>
diff --git a/src/components/Modals/Rss/FeedForm.vue b/src/components/Modals/Rss/FeedForm.vue
index f56fd9d7..d3c69cb1 100644
--- a/src/components/Modals/Rss/FeedForm.vue
+++ b/src/components/Modals/Rss/FeedForm.vue
@@ -1,5 +1,5 @@
 <template>
-  <v-dialog v-model="dialog" content-class="rounded-form" max-width="300px" @keydown.enter.prevent="hasInitialFeed ? edit : create" @keydown.esc.prevent="cancel">
+  <v-dialog v-model="dialog" content-class="rounded-form" max-width="300px" @keydown.enter.prevent="hasInitialFeed ? edit : create">
     <v-card>
       <v-card-title class="pa-0">
         <v-toolbar-title class="ma-4 primarytext--text">
diff --git a/src/components/Modals/Rss/RuleForm.vue b/src/components/Modals/Rss/RuleForm.vue
index 51884b24..50cf0c8d 100644
--- a/src/components/Modals/Rss/RuleForm.vue
+++ b/src/components/Modals/Rss/RuleForm.vue
@@ -1,5 +1,5 @@
 <template>
-  <v-dialog v-model="dialog" max-width="1000px" @keydown.enter.prevent="setRule" @keydown.esc.prevent="close">
+  <v-dialog v-model="dialog" max-width="1000px" @keydown.enter.prevent="setRule">
     <v-card flat :loading="loading">
       <v-container class="pa-0 project done">
         <v-card-title class="justify-center">
diff --git a/src/components/Modals/TagsAndCategories/CreateCategoryDialog.vue b/src/components/Modals/TagsAndCategories/CreateCategoryDialog.vue
index 7778239c..e992fba0 100644
--- a/src/components/Modals/TagsAndCategories/CreateCategoryDialog.vue
+++ b/src/components/Modals/TagsAndCategories/CreateCategoryDialog.vue
@@ -1,5 +1,5 @@
 <template>
-  <v-dialog v-model="dialog" content-class="rounded-form" max-width="300px">
+  <v-dialog v-model="dialog" content-class="rounded-form" max-width="300px" @keydown.enter.prevent="submit">
     <v-card>
       <v-card-title class="pa-0">
         <v-toolbar-title class="ma-4 primarytext--text">
@@ -7,19 +7,17 @@
         </v-toolbar-title>
       </v-card-title>
       <v-card-text>
-        <v-form ref="categoryForm" v-model="valid" class="px-6 mt-3">
-          <v-container>
-            <v-text-field v-model="category.name" :rules="nameRules" :label="$t('modals.newCategory.categoryName')" required :disabled="hasInitialCategory" />
-            <v-text-field v-model="category.savePath" :rules="PathRules" :label="$t('path')" required />
-          </v-container>
-        </v-form>
+        <v-container>
+          <v-text-field v-model="category.name" :rules="nameRules" :label="$t('modals.newCategory.categoryName')" required :disabled="hasInitialCategory" />
+          <v-text-field v-model="category.savePath" :rules="pathRules" :label="$t('path')" required />
+        </v-container>
       </v-card-text>
       <v-divider />
       <v-card-actions class="justify-end">
-        <v-btn v-if="!hasInitialCategory" class="accent white--text elevation-0 px-4" @click="create" :disabled="!valid">
+        <v-btn v-if="!hasInitialCategory" class="accent white--text elevation-0 px-4" @click="create" :disabled="!isValid">
           {{ $t('create') }}
         </v-btn>
-        <v-btn v-else class="accent white--text elevation-0 px-4" @click="edit" :disabled="!valid">
+        <v-btn v-else class="accent white--text elevation-0 px-4" @click="edit" :disabled="!isValid">
           {{ $t('edit') }}
         </v-btn>
         <v-btn class="error white--text elevation-0 px-4" @click="cancel">
@@ -47,8 +45,7 @@ export default {
     category: { name: '', savePath: '' },
     mdiCancel,
     mdiTagPlus,
-    mdiPencil,
-    valid: false
+    mdiPencil
   }),
   computed: {
     ...mapGetters(['getSelectedCategory']),
@@ -58,8 +55,11 @@ export default {
     nameRules() {
       return [v => !!v || this.$t('modals.newCategory.tipOnNoName')]
     },
-    PathRules() {
+    pathRules() {
       return [v => !!v || this.$t('modals.newCategory.tipOnNoPath')]
+    },
+    isValid() {
+      return !!this.category.name && !!this.category.savePath
     }
   },
   created() {
@@ -69,21 +69,28 @@ export default {
     }
   },
   methods: {
+    async submit() {
+      if (this.hasInitialCategory) {
+        await this.edit()
+      } else {
+        await this.create()
+      }
+    },
     async create() {
+      if (!this.isValid) return
       await qbit.createCategory(this.category)
       this.cancel()
     },
+    async edit() {
+      if (!this.isValid) return
+      await qbit.editCategory(this.category)
+      Vue.$toast.success(this.$t('toast.categorySaved'))
+      this.cancel()
+    },
     cancel() {
       this.$store.commit('FETCH_CATEGORIES')
       this.dialog = false
-    },
-    async edit() {
-      await qbit.editCategory(this.category)
-      Vue.$toast.success(this.$t('toast.categorySaved'))
-      this.cancel()
     }
   }
 }
 </script>
-
-<style></style>
diff --git a/src/components/Modals/TagsAndCategories/CreateTagDialog.vue b/src/components/Modals/TagsAndCategories/CreateTagDialog.vue
index d239cd66..b5576e91 100644
--- a/src/components/Modals/TagsAndCategories/CreateTagDialog.vue
+++ b/src/components/Modals/TagsAndCategories/CreateTagDialog.vue
@@ -1,5 +1,5 @@
 <template>
-  <v-dialog v-model="dialog" content-class="rounded-form" max-width="300px">
+  <v-dialog v-model="dialog" content-class="rounded-form" max-width="300px" @keydown.enter.prevent="create">
     <v-card>
       <v-card-title class="pa-0">
         <v-toolbar-title class="ma-4 primarytext--text">
@@ -7,15 +7,13 @@
         </v-toolbar-title>
       </v-card-title>
       <v-card-text>
-        <v-form ref="tagForm" v-model="valid" class="px-6 mt-3">
-          <v-container>
-            <v-text-field v-model="tagname" :rules="rules" :label="$t('modals.newTag.tagName')" required />
-          </v-container>
-        </v-form>
+        <v-container>
+          <v-text-field v-model="tagname" :rules="rules" :label="$t('modals.newTag.tagName')" required />
+        </v-container>
       </v-card-text>
       <v-divider />
       <v-card-actions class="justify-end">
-        <v-btn class="accent white--text elevation-0 px-4" @click="create" :disabled="!valid">
+        <v-btn class="accent white--text elevation-0 px-4" @click="create" :disabled="!isValid">
           {{ $t('create') }}
         </v-btn>
         <v-btn class="error white--text elevation-0 px-4" @click="cancel">
@@ -34,14 +32,19 @@ export default {
   mixins: [Modal],
   data: () => ({
     tagname: '',
-    rules: [v => !!v || 'Tag is required'],
-    valid: false
+    rules: [v => !!v || 'Tag is required']
   }),
+  computed: {
+    isValid() {
+      return !!this.tagname
+    }
+  },
   created() {
     this.$store.commit('FETCH_TAGS')
   },
   methods: {
     async create() {
+      if (!this.isValid) return
       await qbit.createTag([this.tagname])
       this.cancel()
     },
@@ -52,5 +55,3 @@ export default {
   }
 }
 </script>
-
-<style></style>
diff --git a/src/views/RssArticles.vue b/src/views/RssArticles.vue
index 1e671d88..2804d1df 100644
--- a/src/views/RssArticles.vue
+++ b/src/views/RssArticles.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="px-1 px-sm-5 background noselect" @keydown.esc.prevent="close">
+  <div class="px-1 px-sm-5 background noselect">
     <v-row no-gutters class="grey--text" align="center" justify="center">
       <v-col>
         <h1 style="font-size: 1.6em !important" class="subtitle-1 ml-2">
@@ -97,6 +97,12 @@ export default defineComponent({
   created() {
     this.$store.commit('FETCH_FEEDS')
   },
+  mounted() {
+    document.addEventListener('keydown', this.handleKeyboardShortcut)
+  },
+  beforeDestroy() {
+    document.removeEventListener('keydown', this.handleKeyboardShortcut)
+  },
   computed: {
     ...mapState(['rss']),
     articles(): FeedArticle[] {
@@ -133,6 +139,11 @@ export default defineComponent({
         await qbit.markAsRead(article.feedName, article.id)
       }
       this.$store.commit('FETCH_FEEDS')
+    },
+    handleKeyboardShortcut(e: KeyboardEvent) {
+      if (e.key === 'Escape') {
+        this.close()
+      }
     }
   }
 })
diff --git a/src/views/Settings.vue b/src/views/Settings.vue
index b210c735..d66933ce 100644
--- a/src/views/Settings.vue
+++ b/src/views/Settings.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="px-1 px-sm-5 background noselect" @keydown.esc.prevent="close">
+  <div class="px-1 px-sm-5 background noselect">
     <v-row no-gutters class="grey--text" align="center" justify="center">
       <v-col>
         <h1 style="font-size: 1.6em !important" class="subtitle-1 ml-2">
@@ -115,7 +115,7 @@ export default defineComponent({
     }
   },
   computed: {
-    ...mapGetters(['getSettings']),
+    ...mapGetters(['getSettings', 'getModals']),
     settings() {
       return this.getSettings()
     },
@@ -125,6 +125,10 @@ export default defineComponent({
   },
   mounted() {
     this.$store.dispatch('FETCH_SETTINGS')
+    document.addEventListener('keydown', this.handleKeyboardShortcut)
+  },
+  beforeDestroy() {
+    document.removeEventListener('keydown', this.handleKeyboardShortcut)
   },
   watch: {
     tab() {
@@ -134,6 +138,11 @@ export default defineComponent({
   methods: {
     close() {
       this.$router.back()
+    },
+    handleKeyboardShortcut(e: KeyboardEvent) {
+      if (e.key === 'Escape' && this.getModals().length === 0) {
+        this.close()
+      }
     }
   }
 })
diff --git a/src/views/TorrentDetail.vue b/src/views/TorrentDetail.vue
index 9a94d58c..796a3c4d 100644
--- a/src/views/TorrentDetail.vue
+++ b/src/views/TorrentDetail.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="px-1 px-sm-5 background noselect" @keydown.esc.prevent="close">
+  <div class="px-1 px-sm-5 background noselect">
     <v-row no-gutters class="grey--text" align="center" justify="center">
       <v-col>
         <h1 style="font-size: 1.6em !important" class="subtitle-1 ml-2">
@@ -83,13 +83,20 @@ export default {
   },
   mounted() {
     this.$store.dispatch('INIT_INTERVALS')
+    document.addEventListener('keydown', this.handleKeyboardShortcut)
   },
   beforeDestroy() {
     this.$store.commit('REMOVE_INTERVALS')
+    document.removeEventListener('keydown', this.handleKeyboardShortcut)
   },
   methods: {
     close() {
       this.$router.back()
+    },
+    handleKeyboardShortcut(e) {
+      if (e.key === 'Escape') {
+        this.close()
+      }
     }
   }
 }