diff --git a/app/assets/javascripts/keyboard_tools.js b/app/assets/javascripts/keyboard_tools.js
new file mode 100644
index 0000000000000000000000000000000000000000..990dfdc8c7bd68904f42407ed927a9267128cf1f
--- /dev/null
+++ b/app/assets/javascripts/keyboard_tools.js
@@ -0,0 +1,263 @@
+$(() => {
+    _CodidactKeyboard = {
+        state: 'home',
+        selectedItem: null,
+        user_id: parseInt($('.header--item.is-complex.is-visible-on-mobile[href^="/users/"').attr('href').split("/").pop()),
+        is_mod: !!$('.header--item[href="/mod/flags"]').length,
+        categories: function () {
+            category_elements = $("a.category-header--tab");
+            return_obj = {};
+            category_elements.each(function () {
+                return_obj[this.innerText] = this.getAttribute('href');
+            });
+            return return_obj;
+        },
+        dialog: function (msg) {
+            _CodidactKeyboard.dialogClose();
+            d = document.createElement("div")
+            d.classList.add("__keyboard_help");
+            d.innerText = msg;
+            document.body.appendChild(d);
+        },
+        dialogClose: function () {
+            $(".__keyboard_help").remove();
+            _CodidactKeyboard.state = 'home';
+        },
+        updateSelected: function () {
+            $(".__keyboard_selected").removeClass('__keyboard_selected');
+            if (_CodidactKeyboard.selectedItem) {
+                _CodidactKeyboard.selectedItem.classList.add('__keyboard_selected');
+                _CodidactKeyboard.selectedItem.scrollIntoView({ behavior: 'smooth' });
+                _CodidactKeyboard.selectedItem.focus();
+
+                _CodidactKeyboard.selectedItemData = {
+                    type: _CodidactKeyboard.selectedItem.getAttribute("data-ckb-item-type"),
+                    post_id: _CodidactKeyboard.selectedItem.getAttribute("data-ckb-post-id")
+                };
+            }
+        }
+    }
+
+    // Use html, so that all prior attempts to access keyup event have priority
+    $("html").on("keyup", function (e) {
+        if (e.target != document.body) return;
+        if (e.key == "Escape") {
+            _CodidactKeyboard.dialogClose();
+        } else if (_CodidactKeyboard.state == 'home') {
+            homeMenu(e);
+        } else if (_CodidactKeyboard.state == 'goto') {
+            gotoMenu(e);
+        } else if (_CodidactKeyboard.state == 'goto/category') {
+            categoryMenu(e);
+        } else if (_CodidactKeyboard.state == 'goto/category-tags') {
+            categoryTagsMenu(e);
+        } else if (_CodidactKeyboard.state == 'tools') {
+            toolsMenu(e);
+        } else if (_CodidactKeyboard.state == 'tools/vote') {
+            voteMenu(e);
+        }
+    });
+
+    function homeMenu(e) {
+        if (e.key == "?") {
+            _CodidactKeyboard.dialog('Codidact Keyboard Shortcuts\n' +
+                '===========================\n' +
+                '?  Open this help\n' +
+                'n  New post\n' +
+                '   (in current category)\n' +
+                's  Search for something\n' +
+                'g  Go to a page...\n\n' +
+                'a  Go to answer field\n\n' +
+                'Selection shortcuts:\n\n' +
+                'j  Move one item down\n' +
+                'k  Move one item up\n' +
+                't  Use a tool (on selection)\n\n' +
+                '(Selection shortcuts will select\n' +
+                'first post, if none selected)'
+                                
+            );
+        } else if (e.key == 'n') {
+            new_post_link = $('a.category-header--nav-item.is-button').attr('href');
+            if (new_post_link)
+                window.location.href = new_post_link;
+        } else if (e.key == 'g') {
+            _CodidactKeyboard.dialog('Go to ...\n' +
+                '=========\n' +
+                'm  Main page\n' +
+                'u  User list\n' +
+                'h  Help\n' +
+                'p  Your profile page\n' +
+                'c  Category ...\n' +
+                't  Tags of category ...' +
+                (_CodidactKeyboard.is_mod ? '\nf  Flags (mod only)' : '')
+            );
+            _CodidactKeyboard.state = 'goto';
+        } else if (e.key == 'k') {
+            if (_CodidactKeyboard.selectedItem == null) _CodidactKeyboard.selectedItem = $("[data-ckb-list-item]:first-of-type")[0];
+            else {
+                _CodidactKeyboard.selectedItem = $(_CodidactKeyboard.selectedItem).nextAll('[data-ckb-list-item]')[0] || _CodidactKeyboard.selectedItem;
+            }
+            _CodidactKeyboard.updateSelected();
+        } else if (e.key == 'j') {
+            if (_CodidactKeyboard.selectedItem == null) _CodidactKeyboard.selectedItem = $("[data-ckb-list-item]:first-of-type")[0];
+            else {
+                _CodidactKeyboard.selectedItem = $(_CodidactKeyboard.selectedItem).prevAll('[data-ckb-list-item]')[0] || _CodidactKeyboard.selectedItem;
+            }
+            _CodidactKeyboard.updateSelected();
+        } else if (e.key == 't') {
+            if (_CodidactKeyboard.selectedItem == null) _CodidactKeyboard.selectedItem = $("[data-ckb-list-item]:first-of-type")[0];
+            _CodidactKeyboard.updateSelected();
+
+            if (_CodidactKeyboard.selectedItemData.type == "post") {
+                _CodidactKeyboard.dialog('Use tool ...\n' +
+                    '============\n' +
+                    'f  Flag\n' +
+                    'e  Edit\n' +
+                    'c  Comment\n' +
+                    'l  Get permalink\n' +
+                    'h  View history\n' +
+                    'v  Vote ...' +
+                    (_CodidactKeyboard.is_mod ? '\nt  Use tools' : '')
+                );
+                _CodidactKeyboard.state = 'tools';
+            }
+        } else if (e.key == 'a') {
+            cl = $('#answer_body_markdown');
+            cl[0].scrollIntoView({ behavior: "smooth" });
+            cl.focus();
+            _CodidactKeyboard.dialogClose();
+        } else if (e.key == 'Enter') {
+            if (_CodidactKeyboard.selectedItemData.type == "link") {
+                link = $(_CodidactKeyboard.selectedItem).find("[data-ckb-item-link]").attr("href");
+                window.location.href = link;
+            }
+        }
+    }
+
+    function gotoMenu(e) {
+        if (e.key == 'm') {
+            window.location.href = '/';
+        } else if (e.key == 'u') {
+            window.location.href = '/users';
+        } else if (e.key == 'h') {
+            window.location.href = '/help';
+        } else if (e.key == 'p') {
+            window.location.href = '/users/' + _CodidactKeyboard.user_id;
+        } else if (e.key == 'f') {
+            window.location.href = '/mod/flags';
+        } else if (e.key == 'f') {
+            window.location.href = '/mod/flags';
+        } else if (e.key == "t") {
+            data = _CodidactKeyboard.categories();
+            data = Object.entries(data);
+            string_response = "";
+            for (var i = 0; i < data.length; i++) {
+                entry = data[i];
+                string_response += (i + 1) + "  " + entry[0] + "\n"
+            }
+            _CodidactKeyboard.dialog('Go to tags of category ...\n' +
+                '==================\n' +
+                string_response.trim()
+            );
+            _CodidactKeyboard.state = 'goto/category-tags';
+            window.location.href = tlink;
+        } else if (e.key == 'c') {
+            data = _CodidactKeyboard.categories();
+            data = Object.entries(data);
+            string_response = "";
+            for (var i = 0; i < data.length; i++) {
+                entry = data[i];
+                string_response += (i + 1) + "  " + entry[0] + "\n"
+            }
+            _CodidactKeyboard.dialog('Go to category ...\n' +
+                '==================\n' +
+                "c  Category List\n" +
+                string_response.trim()
+            );
+            _CodidactKeyboard.state = 'goto/category';
+        }
+    
+    }
+
+    function categoryMenu(e) {
+        if (e.key == "c") {
+            window.location.href = "/categories";
+        } else {
+            number = parseInt(e.key);
+            if (number != NaN) {
+                data = _CodidactKeyboard.categories();
+                data = Object.entries(data);
+            
+                category = data[number - 1];
+                window.location.href = category[1];
+            }
+        }
+    }
+
+    function categoryTagsMenu(e) {
+        number = parseInt(e.key);
+        if (number != NaN) {
+            data = _CodidactKeyboard.categories();
+            data = Object.entries(data);
+        
+            category = data[number - 1];
+            window.location.href = category[1] + "/tags";
+        }
+    }
+
+    function toolsMenu(e) {
+        if (e.key == 'e') {
+            window.location.href = $(_CodidactKeyboard.selectedItem).find('.tools--item i.fa.fa-pencil-alt').parent().attr("href");
+        } else if (e.key == 'h') {
+            window.location.href = $(_CodidactKeyboard.selectedItem).find('.tools--item i.fa.fa-history').parent().attr("href");
+        } else if (e.key == 'l') {
+            window.location.href = $(_CodidactKeyboard.selectedItem).find('.tools--item i.fa.fa-link').parent().attr("href");
+        } else if (e.key == 'c') {
+            cl = $(_CodidactKeyboard.selectedItem).find('.js-add-comment');
+            cl.nextAll("form").css("display", "block");
+            cl.nextAll("form")[0].scrollIntoView({ behavior: "smooth" });
+            cl.nextAll("form").find(".js-comment-content").focus();
+            _CodidactKeyboard.dialogClose();
+        } else if (e.key == 'f') {
+            cl = $(_CodidactKeyboard.selectedItem).find('.post--action-dialog.js-flag-box');
+            cl.addClass("is-active");
+            cl[0].scrollIntoView({ behavior: "smooth" });
+            cl.find(".js-flag-comment").focus();
+            _CodidactKeyboard.dialogClose();
+        } else if (e.key == 'v') {
+            _CodidactKeyboard.dialog('Vote ...\n' +
+                '========\n' +
+                'u  Up\n' +
+                'd  Down\n' +
+                'c  Close'
+            );
+            _CodidactKeyboard.state = 'tools/vote';
+        } else if (e.key == 't') {
+            cl = $(_CodidactKeyboard.selectedItem).find('a.tools--item i.fa.fa-wrench').parent();
+            cl = $(cl.attr("data-modal"));
+            cl.toggleClass("is-active");
+            cl.focus();
+            _CodidactKeyboard.dialogClose();
+        }
+    
+    }
+
+    function voteMenu(e) {
+        if (e.key == 'u') {
+            cl = $(_CodidactKeyboard.selectedItem).find('.vote-button[data-vote-type="1"]');
+            cl.click();
+            _CodidactKeyboard.dialogClose();
+        } else if (e.key == 'd') {
+            cl = $(_CodidactKeyboard.selectedItem).find('.vote-button[data-vote-type="-1"]');
+            cl.click();
+            _CodidactKeyboard.dialogClose();
+        } else if (e.key == 'c') {
+            cl = $(_CodidactKeyboard.selectedItem).find('.post--action-dialog.js-close-box');
+            cl.addClass("is-active");
+            cl[0].scrollIntoView({ behavior: "smooth" });
+            cl.focus();
+            _CodidactKeyboard.dialogClose();
+        }
+    
+    }
+});
\ No newline at end of file
diff --git a/app/assets/stylesheets/keyboard_tools.scss b/app/assets/stylesheets/keyboard_tools.scss
new file mode 100644
index 0000000000000000000000000000000000000000..385a5517fe2196847b7810dc8eb255b68beb37a8
--- /dev/null
+++ b/app/assets/stylesheets/keyboard_tools.scss
@@ -0,0 +1,15 @@
+.__keyboard_help {
+    padding: 1rem;
+    font-family: monospace;
+    white-space: pre-wrap;
+    width: 350px;
+    background-color: rgba(0,0,0,0.8);
+    color: white;
+    border-radius: 0.25rem;
+    position: fixed;
+    left: 1rem;
+    bottom: 1rem;
+}
+.__keyboard_selected {
+    outline: 0.25rem solid red;
+}
\ No newline at end of file
diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb
index 4d278900e26b22c2fce7f072ce03045b341c028a..513208b5ce6a8216062af3e80b8b5f492b69e702 100644
--- a/app/views/admin/index.html.erb
+++ b/app/views/admin/index.html.erb
@@ -7,93 +7,93 @@
 
 <div class="grid">
   <% if current_user.is_global_admin %>
-    <div class="grid--cell is-4-lg is-6-md is-12-sm">
+    <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
       <div class="widget">
         <div class="widget--body">
           <i class="fas fa-globe has-color-red-700"></i> <i class="fas fa-cogs"></i>
-          <%= link_to 'Global Site Settings', global_settings_path %>
+          <%= link_to 'Global Site Settings', global_settings_path, 'data-ckb-item-link' => '' %>
         </div>
       </div>
     </div>
 
-    <div class="grid--cell is-4-lg is-6-md is-12-sm">
+    <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
       <div class="widget">
         <div class="widget--body">
           <i class="fas fa-globe has-color-red-700"></i> <i class="fas fa-tags"></i>
-          <%= link_to 'Global Tag Sets', global_tag_sets_path %>
+          <%= link_to 'Global Tag Sets', global_tag_sets_path, 'data-ckb-item-link' => '' %>
         </div>
       </div>
     </div>
 
-    <div class="grid--cell is-4-lg is-6-md is-12-sm">
+    <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
       <div class="widget">
         <div class="widget--body">
           <i class="fas fa-globe has-color-red-700"></i> <i class="fas fa-envelope"></i>
-          <%= link_to 'Email Moderators', moderator_email_path %>
+          <%= link_to 'Email Moderators', moderator_email_path, 'data-ckb-item-link' => '' %>
         </div>
       </div>
     </div>
   <% end %>
 
-  <div class="grid--cell is-4-lg is-6-md is-12-sm">
+  <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
     <div class="widget">
       <div class="widget--body">
         <i class="fas fa-cogs"></i>
-        <%= link_to 'Site Settings', site_settings_path %>
+        <%= link_to 'Site Settings', site_settings_path, 'data-ckb-item-link' => '' %>
       </div>
     </div>
   </div>
 
-  <div class="grid--cell is-4-lg is-6-md is-12-sm">
+  <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
     <div class="widget">
       <div class="widget--body">
         <i class="fas fa-tags"></i>
-        <%= link_to 'Tag Sets', tag_sets_path %>
+        <%= link_to 'Tag Sets', tag_sets_path, 'data-ckb-item-link' => '' %>
       </div>
     </div>
   </div>
 
-  <div class="grid--cell is-4-lg is-6-md is-12-sm">
+  <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
     <div class="widget">
       <div class="widget--body">
         <i class="fas fa-sliders-h"></i>
-        <%= link_to 'Privileges', admin_privileges_path %>
+        <%= link_to 'Privileges', admin_privileges_path, 'data-ckb-item-link' => '' %>
       </div>
     </div>
   </div>
 
-  <div class="grid--cell is-4-lg is-6-md is-12-sm">
+  <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
     <div class="widget">
       <div class="widget--body">
         <i class="fas fa-exclamation-triangle"></i>
-        <%= link_to 'Error Reports', admin_error_reports_path %>
+        <%= link_to 'Error Reports', admin_error_reports_path, 'data-ckb-item-link' => '' %>
       </div>
     </div>
   </div>
 
-  <div class="grid--cell is-4-lg is-6-md is-12-sm">
+  <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
     <div class="widget">
       <div class="widget--body">
         <i class="fas fa-hand-paper"></i>
-        <%= link_to 'Close Reasons', close_reasons_path %>
+        <%= link_to 'Close Reasons', close_reasons_path, 'data-ckb-item-link' => '' %>
       </div>
     </div>
   </div>
 
-  <div class="grid--cell is-4-lg is-6-md is-12-sm">
+  <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
     <div class="widget">
       <div class="widget--body">
         <i class="fas fa-balance-scale"></i>
-        <%= link_to 'Licenses', licenses_path %>
+        <%= link_to 'Licenses', licenses_path, 'data-ckb-item-link' => '' %>
       </div>
     </div>
   </div>
 
-  <div class="grid--cell is-4-lg is-6-md is-12-sm">
+  <div class="grid--cell is-4-lg is-6-md is-12-sm" data-ckb-list-item data-ckb-item-type="link">
     <div class="widget">
       <div class="widget--body">
         <i class="fas fa-user-secret"></i>
-        <%= link_to 'Audit Log', audit_log_path %>
+        <%= link_to 'Audit Log', audit_log_path, 'data-ckb-item-link' => '' %>
       </div>
     </div>
   </div>
diff --git a/app/views/posts/_article_list.html.erb b/app/views/posts/_article_list.html.erb
index 4c75f1adfe3b7ee3fc7a98d1c91abec4ba74fd50..c9dbed4f4e3e48fe4bcbd40b4708d1f0ab10f7db 100644
--- a/app/views/posts/_article_list.html.erb
+++ b/app/views/posts/_article_list.html.erb
@@ -1,7 +1,7 @@
 <% active_user = post.last_activity_by || post.user %>
 <% show_type_tag ||= false %>
 <% show_category_tag ||= false %>
-<div class="item-list--item <%= post.deleted ? 'deleted-content' : '' %>">
+<div class="item-list--item <%= post.deleted ? 'deleted-content' : '' %>" data-ckb-list-item data-ckb-item-type="link">
   <div class="item-list--number-value">
     <div class="meter is-question-score">
       <div class="meter--bar is-<%= (post.score * 100).to_i %>%"><%= (post.score * 100).to_i %>%</div>
@@ -18,7 +18,7 @@
       <% if show_category_tag %>
         <span class="badge is-tag is-filled"><%= defined?(@category) ? @category.name : post.category.name %></span>
       <% end %>
-      <%= link_to post.title, share_article_path(post) %>
+      <%= link_to post.title, share_article_path(post), 'data-ckb-item-link' => '' %>
     </div>
     <p class="has-color-tertiary-600 has-float-right post-list--meta">
       last activity <%= time_ago_in_words(post.last_activity) %> ago by <%= link_to active_user.username, user_path(active_user) %>
diff --git a/app/views/posts/_expanded.html.erb b/app/views/posts/_expanded.html.erb
index ff18d9da58109cd3ec817b0eb9b253540296c6a1..4414071db0b5bb0402d4453af1322f6606ccd6bc 100644
--- a/app/views/posts/_expanded.html.erb
+++ b/app/views/posts/_expanded.html.erb
@@ -2,7 +2,7 @@
 <% is_top_level = post.parent_id.nil? %>
 <% has_tags = is_top_level && !post.tag_ids.empty? %>
 
-<div class="post <%= post.meta? ? 'is-meta' : '' %> <%= is_top_level ? '' : 'has-border-bottom-style-solid has-border-bottom-width-1 has-border-color-tertiary-100' %>" data-post-id="<%= post.id %>" id="<%= (is_question ? 'question-' : 'answer-') + post.id.to_s %>">
+<div class="post <%= post.meta? ? 'is-meta' : '' %> <%= is_top_level ? '' : 'has-border-bottom-style-solid has-border-bottom-width-1 has-border-color-tertiary-100' %>" data-post-id="<%= post.id %>" id="<%= (is_question ? 'question-' : 'answer-') + post.id.to_s %>" data-ckb-list-item data-ckb-item-type="post" data-ckb-post-id="<%= post.id %>">
   <% if is_top_level %>
     <h1 class="post--title has-border-top-width-4 has-border-top-style-solid has-border-color-<%= post.meta? ? 'tertiary' : 'primary' %>-400 has-padding-2">
       <%= post.title %>
diff --git a/app/views/posts/_list.html.erb b/app/views/posts/_list.html.erb
index 836e0f8feabc68153d50a2752c0e2b458da22480..22e2d0ec88416c9b854c3915bcc318243c9dee89 100644
--- a/app/views/posts/_list.html.erb
+++ b/app/views/posts/_list.html.erb
@@ -3,7 +3,7 @@
 <% active_user = post.last_activity_by || post.user %>
 <% show_type_tag ||= false %>
 <% show_category_tag ||= false %>
-<div class="item-list--item <%= is_meta ? 'post__meta' : '' %> <%= post.deleted ? 'deleted-content' : '' %>">
+<div class="item-list--item <%= is_meta ? 'post__meta' : '' %> <%= post.deleted ? 'deleted-content' : '' %>" data-ckb-list-item data-ckb-item-type="link">
   <div class="item-list--number-value">
     <div class="meter is-question-score">
       <div class="meter--bar is-<%= (post.score * 100).to_i %>%"><%= (post.score * 100).to_i %>%</div>
@@ -17,7 +17,7 @@
   </div>
   <div class="item-list--text-value is-primary">
     <div class="post-list--title">
-      <%= link_to generic_share_link(post) do %>
+      <%= link_to generic_share_link(post), 'data-ckb-item-link' => '' do %>
         <% if show_category_tag %>
           <span class="badge is-tag is-filled"><%= defined?(@category) ? @category.name : post.category.name %></span>
         <% end %>
diff --git a/app/views/tags/_tag.html.erb b/app/views/tags/_tag.html.erb
index 750f4633a985ce4c767190ff704eeea317ac2f1b..ccb2d56441b9d25af2439c7edcb2fdc86307d82f 100644
--- a/app/views/tags/_tag.html.erb
+++ b/app/views/tags/_tag.html.erb
@@ -1,4 +1,4 @@
-<div class="grid--cell tag-cell <%= params[:hierarchical].present? ? 'is-12-sm is-6' : 'is-4-lg is-6-md is-12-sm' %>">
+<div class="grid--cell tag-cell <%= params[:hierarchical].present? ? 'is-12-sm is-6' : 'is-4-lg is-6-md is-12-sm' %>" data-ckb-list-item data-ckb-item-type="link">
   <% if tag.respond_to?(:path) && tag.path.present? %>
     <span class="has-font-size-caption">
       <% tag.path.split(' > ')[0..-2].each do |tag| %>
@@ -6,7 +6,7 @@
       <% end %>
     </span>
   <% end %>
-  <%= link_to tag.name, tag_path(id: category.id, tag_id: tag.id), class: classes %>
+  <%= link_to tag.name, tag_path(id: category.id, tag_id: tag.id), class: classes, 'data-ckb-item-link' => '' %>
   <span class="has-color-tertiary-900">&times;&nbsp;<%= tag.post_count %></span>
   <% if tag.excerpt.present? %>
     <p class="has-font-size-caption has-color-tertiary-900">
diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb
index 1001e0caf675dcacea13d2c51e2189c634970901..088553c2a61d067866eb7eae2f8ac20f133a0c62 100644
--- a/app/views/users/_user.html.erb
+++ b/app/views/users/_user.html.erb
@@ -1,9 +1,9 @@
-<div class="user-list--user">
+<div class="user-list--user" data-ckb-list-item data-ckb-item-type="link">
   <div class="flex-row-always">
     <div><img src="<%= avatar_url(user) %>" alt="user avatar" height="32" width="32" /></div>
     <div class="user--meta">
       <% user_posts = defined?(@post_counts) ? @post_counts[user.id] : user.posts.count %>
-      <span class="username"><%= link_to  user_path(user), class: "is-not-underlined" do %>
+      <span class="username"><%= link_to  user_path(user), class: "is-not-underlined", 'data-ckb-item-link' => '' do %>
                                <%= user.username %>
                                <% if user.is_admin &&  SiteSetting['AdminBadgeCharacter'] %>
                                  <span class="badge is-user-role"><%= SiteSetting['AdminBadgeCharacter'] %></span>