diff --git a/css/layout-paragraphs-widget.css b/css/layout-paragraphs-widget.css
index 36c820d61a2929f8724dce15ec7899334148765e..a2941fe8b2c8ecb1310e50e14917ee38f2d175b9 100644
--- a/css/layout-paragraphs-widget.css
+++ b/css/layout-paragraphs-widget.css
@@ -71,6 +71,7 @@ fieldset.layout-paragraphs-field > legend {
   text-align: center;
 }
 .layout-paragraphs-field .layout-paragraphs-item,
+.layout-paragraphs-field.is-moving .layout-paragraphs-item:hover,
 .layout-paragraphs-field .layout-paragraphs-disabled-items .layout-paragraphs-item {
   border: 1px solid #ffffff;
   box-sizing: border-box;
@@ -90,8 +91,10 @@ fieldset.layout-paragraphs-field > legend {
   outline: none;
 }
 .layout-paragraphs-field .layout-paragraphs-item:hover,
+.layout-paragraphs-field.is-moving .layout-paragraphs-item.is-moving:hover,
 .layout-paragraphs-field .layout-paragraphs-item:focus,
-.layout-paragraphs-field .layout-paragraphs-item:focus-within {
+.layout-paragraphs-field .layout-paragraphs-item:focus-within,
+.layout-paragraphs-field .layout-paragraphs-item.is-moving {
   border-color: #0074bd;
   outline: none;
 }
@@ -124,13 +127,22 @@ fieldset.layout-paragraphs-field > legend {
   background: none;
 }
 .layout-paragraphs-field .layout-controls {
-  height: 30px;
-  left: 0;
+  height: 28px;
+  left: 2px;
   position: absolute;
-  top: 0;
+  top: 2px;
   width: 90px;
   opacity: 0;
 }
+.layout-paragraphs-field .layout-paragraphs-moving-message {
+  position: absolute;
+  padding: 3px 0;
+  width: 100%;
+  text-align: center;
+  background: #efefef;
+  top: 0px;
+  left: 0;
+}
 
 .layout-paragraphs-field .layout-paragraphs-item:hover > .layout-controls,
 .layout-paragraphs-field .layout-paragraphs-item:focus-within > .layout-controls {
@@ -147,14 +159,14 @@ fieldset.layout-paragraphs-field > legend {
 .layout-up {
   cursor: pointer;
   display: block;
-  height: 30px;
+  height: 28px;
   left: 0;
   overflow: hidden;
   opacity: .75;
   position: absolute;
   top: 0;
   text-indent: 100%;
-  width: 30px;
+  width: 28px;
   margin: 0;
   padding: 0;
   border: none;
@@ -168,6 +180,7 @@ fieldset.layout-paragraphs-field > legend {
   opacity: 1;
   cursor: pointer;
 }
+.layout-handle:focus,
 .layout-down:focus,
 .layout-up:focus {
   opacity: 1;
@@ -200,12 +213,8 @@ fieldset.layout-paragraphs-field > legend {
 .reversed .layout-up {
   background-image: url(../img/icon-up--reversed.png);
 }
-.layout-paragraphs-item:first-child > .layout-controls .layout-up {
-  pointer-events: none;
-  opacity: .15;
-}
-.layout-paragraphs-layout .layout-paragraphs-item:nth-last-child(2) > .layout-controls .layout-down,
-.active-items > .layout-paragraphs-item:last-child > .layout-controls .layout-down {
+.layout-down:disabled,
+.layout-up:disabled {
   pointer-events: none;
   opacity: .15;
 }
@@ -218,8 +227,8 @@ fieldset.layout-paragraphs-field > legend {
 .layout-paragraphs-field .layout-paragraphs-actions,
 .gu-mirror .layout-paragraphs-actions {
   position: absolute;
-  right: 0;
-  top: 0;
+  right: 2px;
+  top: 2px;
   padding: 0;
   margin: 0;
   visibility: hidden;
@@ -231,8 +240,8 @@ fieldset.layout-paragraphs-field > legend {
 .layout-paragraphs-field .layout-paragraphs-actions input.layout-paragraphs-edit,
 .layout-paragraphs-field .layout-paragraphs-actions input.layout-paragraphs-remove {
   cursor: pointer;
-  height: 30px;
-  width: 30px;
+  height: 28px;
+  width: 28px;
   margin: 0;
   text-indent: 100%;
   overflow: hidden;
@@ -281,8 +290,8 @@ fieldset.layout-paragraphs-field > legend {
 .layout-paragraphs-add-content__toggle {
   position: absolute;
   left: 50%;
-  margin-left: -11px;
-  margin-top: -11px;
+  margin-left: -15px;
+  margin-top: -15px;
   border: none;
   color: #fff;
   font-weight: bold;
@@ -291,8 +300,8 @@ fieldset.layout-paragraphs-field > legend {
   padding: 0;
   opacity: .75;
   font-size: large;
-  width: 22px;
-  height: 22px;
+  width: 30px;
+  height: 30px;
   text-indent: 100%;
   overflow: hidden;
   background: url(../img/icon-add.png) 0 0 no-repeat;
diff --git a/js/layout-paragraphs-widget.js b/js/layout-paragraphs-widget.js
index 12f6cfa3b718a2ceec8248d2adb1092d6b5130d3..488ff0ba4e5b5be86c44dbfb8952ba02ceda3b8f 100644
--- a/js/layout-paragraphs-widget.js
+++ b/js/layout-paragraphs-widget.js
@@ -100,86 +100,17 @@
     }
   }
   /**
-   * Moves an layout-paragraphs item up.
-   * @param {event} e DOM Event (i.e. click).
-   * @return {bool} Returns false if state is still loading.
+   * Disables layout controls based on their position.
+   * @param {jQuery} $container The jQuery field container object.
    */
-  function moveUp(e) {
-    const $btn = $(e.currentTarget);
-    const $item = $btn.parents(".layout-paragraphs-item:first");
-    const $container = $item.parent();
-
-    if (isLoading($item)) {
-      return false;
-    }
-
-    // We're first, jump up to next available region.
-    if ($item.prev(".layout-paragraphs-item").length === 0) {
-      // Previous region, same layout.
-      if ($container.prev(".layout-paragraphs-layout-region").length) {
-        $container.prev(".layout-paragraphs-layout-region").append($item);
-      }
-      // Otherwise jump to last region in previous layout.
-      else if (
-        $container
-          .closest(".layout-paragraphs-layout")
-          .prev()
-          .find(".layout-paragraphs-layout-region:last-child").length
-      ) {
-        $container
-          .closest(".layout-paragraphs-layout")
-          .prev()
-          .find(
-            ".layout-paragraphs-layout-region:last-child .layout-paragraphs-add-content__container"
-          )
-          .before($item);
-      }
-    } else {
-      $item.after($item.prev());
-    }
-    updateFields($container.closest(".layout-paragraphs-field"));
-    return false;
-  }
-  /**
-   * Moves an layout-paragraphs item down.
-   * @param {event} e DOM Event (i.e. click).
-   * @return {bool} Returns false if state is still loading.
-   */
-  function moveDown(e) {
-    const $btn = $(e.currentTarget);
-    const $item = $btn.parents(".layout-paragraphs-item:first");
-    const $container = $item.parent();
-
-    if (isLoading($item)) {
-      return false;
-    }
-
-    // We're first, jump down to next available region.
-    if ($item.next(".layout-paragraphs-item").length === 0) {
-      // Next region, same layout.
-      if ($container.next(".layout-paragraphs-layout-region").length) {
-        $container.next(".layout-paragraphs-layout-region").prepend($item);
-      }
-      // Otherwise jump to first region in next layout.
-      else if (
-        $container
-          .closest(".layout-paragraphs-layout")
-          .next()
-          .find(".layout-paragraphs-layout-region:first-child").length
-      ) {
-        $container
-          .closest(".layout-paragraphs-layout")
-          .next()
-          .find(
-            ".layout-paragraphs-layout-region:first-child .layout-paragraphs-add-content__container"
-          )
-          .before($item);
-      }
-    } else {
-      $item.before($item.next());
-    }
-    updateFields($container.closest(".layout-paragraphs-field"));
-    return false;
+  function updateLayoutControls($container) {
+    $(".layout-up, .layout-down", $container).prop("disabled", false);
+    $(
+      ".layout-paragraphs-item:first-child > .layout-controls > .layout-up, .layout-paragraphs-item:last-child > .layout-controls > .layout-down",
+      $container
+    )
+      .blur()
+      .prop("disabled", true);
   }
   /**
    * Closes the "add paragraph item" menu.
@@ -222,7 +153,8 @@
     const btnHeight = $btn.height();
     const menuHeight = $menu.outerHeight();
     // Account for rotation with slight padding.
-    const left = btnWidth / 4 + Math.floor(btnOffset.left + btnWidth / 2 - menuWidth / 2);
+    const left =
+      btnWidth / 4 + Math.floor(btnOffset.left + btnWidth / 2 - menuWidth / 2);
 
     // Default to positioning the menu beneath the button.
     let orientation = "beneath";
@@ -288,13 +220,6 @@
         .find(".layout-paragraphs-add-more-menu__search")
         .removeClass("hidden");
     }
-    if (
-      !$menu.find(".layout-paragraphs-add-more-menu__search").hasClass("hidden")
-    ) {
-      $menu
-        .find('.layout-paragraphs-add-more-menu__search input[type="text"]')
-        .focus();
-    }
     $menu.data("activeButton", $btn);
     // Make other buttons inactive.
     $widget
@@ -317,6 +242,20 @@
 
     setTimeout(() => {
       positionMenu($menu);
+      if (
+        !$menu
+          .find(".layout-paragraphs-add-more-menu__search")
+          .hasClass("hidden")
+      ) {
+        $menu
+          .find('.layout-paragraphs-add-more-menu__search input[type="text"]')
+          .focus();
+      } else {
+        $menu
+          .find("a")
+          .first()
+          .focus();
+      }
     }, 100);
     window.addEventListener("click", handleClickOutsideMenu);
   }
@@ -379,7 +318,7 @@
   }
   /**
    * Removes all toggle buttons.
-   * @param {*} $container
+   * @param {jQuery} $container The jQuery widget object.
    */
   function removeToggleButtons($container) {
     $(".layout-paragraphs-add-content__toggle", $container).remove();
@@ -389,7 +328,8 @@
    * @param {jQuery} $container The jQuery layout-paragraphs Field container.
    * @param {Object} widgetSettings The widget settings object.
    */
-  function toggleButtons($container, widgetSettings) {
+  function toggleButtons($container) {
+    const widgetSettings = $container.data("widgetSettings");
     $(".layout-paragraphs-add-content__toggle", $container).remove();
     if (widgetSettings.isTranslating) {
       return;
@@ -466,6 +406,229 @@
       );
     }
   }
+  /**
+   * Runs all necessary updates to widget.
+   * @param {jQuery} $widget The jQuery widget item.
+   */
+  function updateWidget($widget) {
+    toggleButtons($widget);
+    updateFields($widget);
+    updateDisabled($widget);
+    updateLayoutControls($widget);
+  }
+  function move(e) {
+    const { $layoutItem } = e.data;
+    const $widget = $layoutItem.closest(".layout-paragraphs-field");
+    const widgetSettings = $widget.data("widgetSettings");
+    const maxDepth = widgetSettings.maxDepth;
+    let dir;
+
+    switch (e.keyCode) {
+      case 37:
+      case 38:
+        dir = "up";
+        break;
+      case 39:
+      case 40:
+        dir = "down";
+        break;
+      default:
+        dir = "stop";
+        break;
+    }
+    const $next = dir === "up" ? $layoutItem.prev() : $layoutItem.next();
+
+    switch (dir) {
+      case "up":
+        if ($next.length) {
+          if ($next.hasClass("layout-paragraphs-layout")) {
+            $(
+              $next
+                .find(".layout-paragraphs-layout-region")
+                .last()
+                .append($layoutItem)
+            );
+          } else if ($next.hasClass("layout-paragraphs-item")) {
+            $next.before($layoutItem);
+          }
+        } else if (
+          $layoutItem
+            .parent()
+            .prev()
+            .hasClass("layout-paragraphs-layout-region")
+        ) {
+          $layoutItem
+            .parent()
+            .prev()
+            .append($layoutItem);
+        } else if (
+          $layoutItem.parent().hasClass("layout-paragraphs-layout-region")
+        ) {
+          $layoutItem
+            .parents(".layout-paragraphs-item")
+            .last()
+            .before($layoutItem);
+        } else if (
+          $layoutItem
+            .parent()
+            .hasClass("layout-paragraphs-disabled-items__items")
+        ) {
+          $widget.find(".active-items").append($layoutItem);
+        }
+        break;
+      case "down":
+        if ($next.length) {
+          if ($next.hasClass("layout-paragraphs-layout")) {
+            $(
+              $next
+                .find(".layout-paragraphs-layout-region")
+                .first()
+                .prepend($layoutItem)
+            );
+          } else if ($next.hasClass("layout-paragraphs-item")) {
+            $next.after($layoutItem);
+          }
+        } else if (
+          $layoutItem
+            .parent()
+            .next()
+            .hasClass("layout-paragraphs-layout-region")
+        ) {
+          $layoutItem
+            .parent()
+            .next()
+            .prepend($layoutItem);
+        } else if (
+          $layoutItem.parent().hasClass("layout-paragraphs-layout-region")
+        ) {
+          $layoutItem
+            .parents(".layout-paragraphs-item")
+            .first()
+            .after($layoutItem);
+        } else if ($layoutItem.parent().hasClass("active-items")) {
+          $widget
+            .find(".layout-paragraphs-disabled-items__items")
+            .prepend($layoutItem);
+        }
+        break;
+      case "stop":
+        $(document).unbind("keydown", move);
+        $widget
+          .removeClass("is-moving")
+          .find(".is-moving")
+          .removeClass("is-moving");
+        $widget.find(".layout-controls, .layout-paragraphs-actions").show();
+        updateWidget($widget);
+        break;
+      default:
+        break;
+    }
+    $widget.find(".layout-paragraphs-moving-message").remove();    
+    return false;
+  }
+  function startMove(e) {
+    const $item = $(e.currentTarget).closest(".layout-paragraphs-item");
+    const $widget = $item.closest(".layout-paragraphs-field");
+    $(e.currentTarget)
+      .parent(".layout-controls")
+      .after(
+        $(
+          `<div class="layout-paragraphs-moving-message">${Drupal.t(
+            "Use arrow keys to move, any other key to stop."
+          )}</div>`
+        )
+      );
+    removeToggleButtons($widget);
+    $widget.find(".layout-controls, .layout-paragraphs-actions").hide();
+    $item.addClass("is-moving");
+    $widget.addClass("is-moving");
+    $(document).bind("keydown", { $layoutItem: $item }, move);
+    return false;
+  }
+  /**
+   * Moves an layout-paragraphs item up.
+   * @param {event} e DOM Event (i.e. click).
+   * @return {bool} Returns false if state is still loading.
+   */
+  function moveUp(e) {
+    const $btn = $(e.currentTarget);
+    const $item = $btn.parents(".layout-paragraphs-item:first");
+    const $container = $item.parent();
+    const $widget = $btn.closest(".layout-paragraphs-field");
+
+    if (isLoading($item)) {
+      return false;
+    }
+
+    // We're first, jump up to next available region.
+    if ($item.prev(".layout-paragraphs-item").length === 0) {
+      // Previous region, same layout.
+      if ($container.prev(".layout-paragraphs-layout-region").length) {
+        $container.prev(".layout-paragraphs-layout-region").append($item);
+      }
+      // Otherwise jump to last region in previous layout.
+      else if (
+        $container
+          .closest(".layout-paragraphs-layout")
+          .prev()
+          .find(".layout-paragraphs-layout-region:last-child").length
+      ) {
+        $container
+          .closest(".layout-paragraphs-layout")
+          .prev()
+          .find(
+            ".layout-paragraphs-layout-region:last-child .layout-paragraphs-add-content__container"
+          )
+          .before($item);
+      }
+    } else {
+      $item.after($item.prev());
+    }
+    updateWidget($widget);
+    return false;
+  }
+  /**
+   * Moves an layout-paragraphs item down.
+   * @param {event} e DOM Event (i.e. click).
+   * @return {bool} Returns false if state is still loading.
+   */
+  function moveDown(e) {
+    const $btn = $(e.currentTarget);
+    const $item = $btn.parents(".layout-paragraphs-item:first");
+    const $container = $item.parent();
+    const $widget = $btn.closest(".layout-paragraphs-field");
+
+    if (isLoading($item)) {
+      return false;
+    }
+
+    // We're first, jump down to next available region.
+    if ($item.next(".layout-paragraphs-item").length === 0) {
+      // Next region, same layout.
+      if ($container.next(".layout-paragraphs-layout-region").length) {
+        $container.next(".layout-paragraphs-layout-region").prepend($item);
+      }
+      // Otherwise jump to first region in next layout.
+      else if (
+        $container
+          .closest(".layout-paragraphs-layout")
+          .next()
+          .find(".layout-paragraphs-layout-region:first-child").length
+      ) {
+        $container
+          .closest(".layout-paragraphs-layout")
+          .next()
+          .find(
+            ".layout-paragraphs-layout-region:first-child .layout-paragraphs-add-content__container"
+          )
+          .before($item);
+      }
+    } else {
+      $item.before($item.next());
+    }
+    updateWidget($widget);
+    return false;
+  }
   /**
    * Initiates dragula drag/drop functionality.
    * @param {object} $widget ERL field item to attach drag/drop behavior to.
@@ -526,8 +689,7 @@
         }
       });
       drake.on("drop", el => {
-        updateFields($(el).closest(".layout-paragraphs-field"));
-        updateDisabled($(el).closest(".layout-paragraphs-field"));
+        updateWidget($(el).closest(".layout-paragraphs-field"));
       });
       drake.on("drag", el => {
         removeToggleButtons($(el).closest(".layout-paragraphs-field"));
@@ -609,6 +771,7 @@
     }
   };
   Drupal.layoutParagraphsWidget = ($widget, widgetSettings) => {
+    $widget.data("widgetSettings", widgetSettings);
     /**
      * Hide all "add paragraph item" buttons if we have reached cardinality.
      */
@@ -712,7 +875,7 @@
       .once("layout-paragraphs-controls")
       .each((layoutParagraphsItemIndex, layoutParagraphsItem) => {
         $('<div class="layout-controls">')
-          .append($('<div class="layout-handle">'))
+          .append($('<button class="layout-handle">').click(startMove))
           .append(
             $(
               `<button class="layout-up">${Drupal.t("Move up")}</button>`
@@ -746,9 +909,7 @@
      * Update weights, regions, and disabled area on load.
      * Runs every time DOM is updated.
      */
-    toggleButtons($widget, widgetSettings);
-    updateFields($widget);
-    updateDisabled($widget);
+    updateWidget($widget);
     /**
      * Dialog close buttons should trigger the "Cancel" action.
      */
diff --git a/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php b/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php
index 3a53fd8a6c7f8e6f9d5a0856c3ad7d4cb7c58f71..6345b71decdfcb4590fe9f16ee743750a91e0101 100644
--- a/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php
+++ b/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php
@@ -750,6 +750,9 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
       '#attributes' => ['class' => ['layout-paragraphs-disabled-items']],
       '#weight' => 999,
       '#title' => $this->t('Disabled Items'),
+      'description' => [
+        '#markup' => '<div class="layout-paragraphs-disabled-items__description">' . $this->t('Drop items here that you want to keep disabled / hidden, without removing them permanently.') . '</div>',
+      ],
       'items' => [
         '#type' => 'container',
         '#attributes' => [
@@ -757,9 +760,6 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
             'layout-paragraphs-disabled-items__items',
           ],
         ],
-        'description' => [
-          '#markup' => '<div class="layout-paragraphs-disabled-items__description">' . $this->t('Drop items here that you want to keep disabled / hidden, without removing them permanently.') . '</div>',
-        ],
       ],
     ];
 
@@ -1337,7 +1337,10 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
       $radio_element = $element[$key];
       $radio_with_icon_element = [
         '#type' => 'container',
-        '#attributes' => ['class' => ['layout-select--list-item']],
+        '#attributes' => [
+          'class' => ['layout-select--list-item'],
+          'tabindex' => 0,
+        ],
         'icon' => [
           '#type' => 'inline_template',
           '#template' => '<div class="layout-icon-wrapper">{{ img }}</div>',