diff --git a/css/builder.css b/css/builder.css
index e030293ebf5d366c047205f6af02395759e52896..c629481a538f6db0a48f5dad37b97c9a8af31597 100644
--- a/css/builder.css
+++ b/css/builder.css
@@ -76,7 +76,9 @@
   outline: none;
 }
 .lp-builder.is-dragging .js-lpb-region,
-.lp-builder.is-dragging .js-lpb-component {
+.lp-builder.is-navigating .js-lpb-region,
+.lp-builder.is-dragging .js-lpb-component,
+.lp-builder.is-navigating .js-lpb-component:not([data-focus="true"]) {
   outline: 1px dotted blue;
 }
 
diff --git a/js/builder.js b/js/builder.js
index 851ddff5adccd85b9797a936da5ceb410db45c29..cd6819525e9f5357ed65ffa31f7e65f9b12fcdc5 100644
--- a/js/builder.js
+++ b/js/builder.js
@@ -1,16 +1,19 @@
-(($, Drupal, debounce, Sortable, once) => {
+(($, Drupal, drupalSettings, debounce, Sortable, once) => {
   const idAttr = 'data-lpb-id';
 
   /**
    * Removes focus data attributes from all components.
    */
   function unfocusComponents() {
-    document.querySelectorAll('[data-focus="true"]').forEach((element) => {
+    Array.from(document.querySelectorAll('[data-focus="true"]')).forEach((element) => {
       element.removeAttribute('data-focus');
     });
-    document.querySelectorAll('[data-focus-within="true"]').forEach((element) => {
+    Array.from(document.querySelectorAll('[data-focus-within="true"]')).forEach((element) => {
       element.removeAttribute('data-focus-within');
     });
+    Array.from(document.querySelectorAll('.is-navigating')).forEach((element) => {
+      element.classList.remove('is-navigating');
+    });
   }
 
   /**
@@ -132,13 +135,33 @@
   });
 
   document.addEventListener('keydown', (event) => {
-    if (event.key === 'Delete' || event.key === 'Backspace') {
-      const focused = document.querySelector('.js-lpb-component[data-focus="true"]');
-      if (focused) {
+    const focused = document.querySelector('.js-lpb-component[data-focus="true"]');
+    if (!focused) {
+      return;
+    }
+    const layoutId = focused.closest(`[${idAttr}]`).getAttribute(idAttr);
+    const settings = drupalSettings.lpBuilder[layoutId];
+    switch (event.key) {
+      case 'Delete':
+      case 'Backspace':
         focused.querySelector('.lpb-delete').click();
-      }
+        break;
+      case 'ArrowUp':
+      case 'ArrowLeft':
+        nav(focused, -1, settings);
+        event.preventDefault();
+        event.stopPropagation();
+        break;
+      case 'ArrowDown':
+      case 'ArrowRight':
+        nav(focused, 1, settings);
+        event.preventDefault();
+        event.stopPropagation();
+        break;
+      default:
+        break;
     }
-  })
+  });
 
   /**
    * Attaches UI elements to $container.
@@ -373,99 +396,73 @@
 
   /**
    * Moves the focused component up or down the DOM to the next valid position
-   * when an arrow key is pressed. Unlike move(), nav()can fully navigate
+   * when an arrow key is pressed. Unlike move(), nav() can fully navigate
    * components to any valid position in an entire layout.
-   * @param {jQuery} $item The jQuery item to move.
+   * @param {HTMLElement} element The component to move.
    * @param {int} dir The direction to move (1 == down, -1 == up).
    * @param {Object} settings The builder ui settings.
    */
-  function nav($item, dir, settings) {
-    const $element = $item.closest(`[${idAttr}]`);
-    $item.addClass('lpb-active-item');
+  function nav(element, dir, settings) {
+    const layoutContainer = element.closest(`[${idAttr}]`);
+    layoutContainer.classList.add('is-navigating');
+
+    element.classList.add('lpb-active-item');
+
     // Add shims as target elements.
-    if (dir === -1) {
-      $(
-        '.js-lpb-region .lpb-btn--add.center, .lpb-layout:not(.lpb-active-item)',
-        $element,
-      ).before('<div class="lpb-shim"></div>');
-    } else if (dir === 1) {
-      $('.js-lpb-region', $element).prepend('<div class="lpb-shim"></div>');
-      $('.lpb-layout:not(.lpb-active-item)', $element).after(
-        '<div class="lpb-shim"></div>',
-      );
+    if (dir < 0) {
+      layoutContainer.querySelectorAll('.js-lpb-region .lpb-btn--add.center, .lpb-layout:not(.lpb-active-item)').forEach(el => {
+        const shim = document.createElement('div');
+        shim.className = 'lpb-shim';
+        el.parentNode.insertBefore(shim, el);
+      });
+    } else if (dir > 0 ) {
+      layoutContainer.querySelectorAll('.js-lpb-region').forEach(region => {
+        const shim = document.createElement('div');
+        shim.className = 'lpb-shim';
+        region.prepend(shim);
+      });
+      layoutContainer.querySelectorAll('.lpb-layout:not(.lpb-active-item)').forEach(layout => {
+        const shim = document.createElement('div');
+        shim.className = 'lpb-shim';
+        layout.parentNode.insertBefore(shim, layout.nextSibling);
+      });
     }
+
     // Build a list of possible targets, or move destinations.
-    const targets = $('.js-lpb-component, .lpb-shim', $element)
-      .toArray()
-      // Remove child components from possible targets.
-      .filter((i) => !$.contains($item[0], i))
-      // Remove layout elements that are not self from possible targets.
-      .filter(
-        (i) => i.className.indexOf('lpb-layout') === -1 || i === $item[0],
-      );
-    const currentElement = $item[0];
+    let targets = Array.from(layoutContainer.querySelectorAll('.js-lpb-component, .lpb-shim'))
+      .filter(i => !(element !== i && element.contains(i)))
+      .filter(i => !(i.classList.contains('lpb-layout') && i !== element));
+
+    const currentElement = element;
     let pos = targets.indexOf(currentElement);
+
     // Check to see if the next position is allowed by calling the 'accepts' callback.
     while (
       targets[pos + dir] !== undefined &&
       acceptsErrors(
         settings,
-        $item[0],
+        element,
         targets[pos + dir].parentNode,
         null,
-        $item.next().length ? $item.next()[0] : null,
+        element.nextElementSibling || null
       ).length > 0
     ) {
       pos += dir;
     }
+
     if (targets[pos + dir] !== undefined) {
-      // Move after or before the target based on direction.
-      $(targets[pos + dir])[dir === 1 ? 'after' : 'before']($item);
+      const target = targets[pos + dir];
+      target.insertAdjacentElement(dir === 1 ? 'afterend' : 'beforebegin', element);
     }
-    // Remove the shims and save the order.
-    $('.lpb-shim', $element).remove();
-    $item.removeClass('lpb-active-item').focus();
-    $item
-      .closest(`[${idAttr}]`)
-      .trigger('lpb-component:move', [$item.attr('data-uuid')]);
-  }
 
-  function startNav($item) {
-    const $msg = $(
-      `<div id="lpb-navigating-msg" class="lpb-tooltiptext lpb-tooltiptext--visible js-lpb-tooltiptext">${Drupal.t(
-        'Use arrow keys to move. Press Return or Tab when finished.',
-      )}</div>`,
-    );
-    $item
-      .closest('.lp-builder')
-      .addClass('is-navigating')
-      .find('.is-navigating')
-      .removeClass('is-navigating');
-    $item
-      .attr('aria-describedby', 'lpb-navigating-msg')
-      .addClass('is-navigating')
-      .prepend($msg);
-    $item.before('<div class="lpb-navigating-placeholder"></div>');
-  }
-
-  function stopNav($item) {
-    $item
-      .removeClass('is-navigating')
-      .attr('aria-describedby', '')
-      .find('.js-lpb-tooltiptext')
-      .remove();
-    $item
-      .closest(`[${idAttr}]`)
-      .removeClass('is-navigating')
-      .find('.lpb-navigating-placeholder')
-      .remove();
-  }
+    // Remove the shims and save the order.
+    layoutContainer.querySelectorAll('.lpb-shim').forEach(shim => shim.remove());
+    element.classList.remove('lpb-active-item');
+    element.focus();
 
-  function cancelNav($item) {
-    const $builder = $item.closest(`[${idAttr}]`);
-    $builder.find('.lpb-navigating-placeholder').replaceWith($item);
-    updateUi($builder[0]);
-    stopNav($item);
+    layoutContainer.dispatchEvent(new CustomEvent('lpb-component:move', {
+      detail: element.getAttribute('data-uuid')
+    }));
   }
 
   /**
@@ -519,30 +516,6 @@
       startNav($btn.closest('.js-lpb-component'));
     });
     $(document).off('keydown');
-    $(document).on('keydown', (e) => {
-      const $item = $('.js-lpb-component.is-navigating');
-      if ($item.length) {
-        switch (e.code) {
-          case 'ArrowUp':
-          case 'ArrowLeft':
-            nav($item, -1, settings);
-            break;
-          case 'ArrowDown':
-          case 'ArrowRight':
-            nav($item, 1, settings);
-            break;
-          case 'Enter':
-          case 'Tab':
-            stopNav($item);
-            break;
-          case 'Escape':
-            cancelNav($item);
-            break;
-          default:
-            break;
-        }
-      }
-    });
   }
 
   /**
@@ -901,4 +874,4 @@
   } else {
     window.addEventListener('dialog:aftercreate', handleAfterDialogCreate);
   }
-})(jQuery, Drupal, Drupal.debounce, Sortable, once);
+})(jQuery, Drupal, drupalSettings, Drupal.debounce, Sortable, once);