diff --git a/core/modules/layout_builder/css/layout-builder.css b/core/modules/layout_builder/css/layout-builder.css
index 900329e8edfd997ded5f2626f32b6e81a4cd7e4d..29f9a2b2055e8d4027c364ed0d0b3f1edbde0017 100644
--- a/core/modules/layout_builder/css/layout-builder.css
+++ b/core/modules/layout_builder/css/layout-builder.css
@@ -68,6 +68,7 @@
   border-radius: 26px;
   margin-left: -10px;
   margin-right: 6px;
+  z-index: 2;
 }
 
 .layout-builder__link--remove:hover {
@@ -121,3 +122,22 @@
   display: block;
   padding: 15px 0 15px 25px;
 }
+
+.layout-builder__add-section.is-layout-builder-highlighted {
+  margin-bottom: calc(1.5em - 8px);
+  outline: none;
+}
+.layout-builder__layout.is-layout-builder-highlighted,
+.layout-builder-block.is-layout-builder-highlighted,
+.layout-builder__add-block.is-layout-builder-highlighted {
+  margin: -4px -2px;
+  position: relative;
+  z-index: 1;
+}
+.layout-builder__add-block.is-layout-builder-highlighted,
+.layout-builder__add-section.is-layout-builder-highlighted,
+.layout-builder__layout.is-layout-builder-highlighted:before,
+.layout-builder__layout.is-layout-builder-highlighted,
+.layout-builder-block.is-layout-builder-highlighted {
+  border: 4px solid #000;
+}
diff --git a/core/modules/layout_builder/js/layout-builder.es6.js b/core/modules/layout_builder/js/layout-builder.es6.js
index bdd17e3e5b693a71cfe8ceb3c3084c5f198a3b81..6b25f4e4e876dd21678cbaf4e1070d5c3dd8efd4 100644
--- a/core/modules/layout_builder/js/layout-builder.es6.js
+++ b/core/modules/layout_builder/js/layout-builder.es6.js
@@ -201,4 +201,86 @@
         .attr('tabindex', -1);
     },
   };
+
+  // After a dialog opens, highlight element that the dialog is acting on.
+  $(window).on('dialog:aftercreate', (event, dialog, $element) => {
+    if (Drupal.offCanvas.isOffCanvas($element)) {
+      // Start by removing any existing highlighted elements.
+      $('.is-layout-builder-highlighted').removeClass(
+        'is-layout-builder-highlighted',
+      );
+
+      /*
+       * Every dialog has a single 'data-layout-builder-target-highlight-id'
+       * attribute. Every dialog-opening element has a unique
+       * 'data-layout-builder-highlight-id' attribute.
+       *
+       * When the value of data-layout-builder-target-highlight-id matches
+       * an element's value of data-layout-builder-highlight-id, the class
+       * 'is-layout-builder-highlighted' is added to element.
+       */
+      const id = $element
+        .find('[data-layout-builder-target-highlight-id]')
+        .attr('data-layout-builder-target-highlight-id');
+      if (id) {
+        $(`[data-layout-builder-highlight-id="${id}"]`).addClass(
+          'is-layout-builder-highlighted',
+        );
+      }
+    }
+  });
+
+  /*
+   * When a Layout Builder dialog is triggered, the main canvas resizes. After
+   * the resize transition is complete, see if the target element is still
+   * visible in viewport. If not, scroll page so the target element is again
+   * visible.
+   *
+   * @todo Replace this custom solution when a general solution is made
+   *   available with https://www.drupal.org/node/3033410
+   */
+  if (document.querySelector('[data-off-canvas-main-canvas]')) {
+    const mainCanvas = document.querySelector('[data-off-canvas-main-canvas]');
+
+    // This event fires when canvas CSS transitions are complete.
+    mainCanvas.addEventListener('transitionend', () => {
+      const $target = $('.is-layout-builder-highlighted');
+
+      if ($target.length > 0) {
+        // These four variables are used to determine if the element is in the
+        // viewport.
+        const targetTop = $target.offset().top;
+        const targetBottom = targetTop + $target.outerHeight();
+        const viewportTop = $(window).scrollTop();
+        const viewportBottom = viewportTop + $(window).height();
+
+        // If the element is not in the viewport, scroll it into view.
+        if (targetBottom < viewportTop || targetTop > viewportBottom) {
+          const viewportMiddle = (viewportBottom + viewportTop) / 2;
+          const scrollAmount = targetTop - viewportMiddle;
+
+          // Check whether the browser supports scrollBy(options). If it does
+          // not, use scrollBy(x-coord, y-coord) instead.
+          if ('scrollBehavior' in document.documentElement.style) {
+            window.scrollBy({
+              top: scrollAmount,
+              left: 0,
+              behavior: 'smooth',
+            });
+          } else {
+            window.scrollBy(0, scrollAmount);
+          }
+        }
+      }
+    });
+  }
+
+  // When a dialog closes, remove the highlight from all elements.
+  $(window).on('dialog:afterclose', (event, dialog, $element) => {
+    if (Drupal.offCanvas.isOffCanvas($element)) {
+      $('.is-layout-builder-highlighted').removeClass(
+        'is-layout-builder-highlighted',
+      );
+    }
+  });
 })(jQuery, Drupal);
diff --git a/core/modules/layout_builder/js/layout-builder.js b/core/modules/layout_builder/js/layout-builder.js
index b6cb26ca1e04acf50b2bb4d378a820b26a88ece1..13b6b09aa627899f4efcbf547a9f71078ba99401 100644
--- a/core/modules/layout_builder/js/layout-builder.js
+++ b/core/modules/layout_builder/js/layout-builder.js
@@ -93,4 +93,51 @@
       }).attr('tabindex', -1);
     }
   };
+
+  $(window).on('dialog:aftercreate', function (event, dialog, $element) {
+    if (Drupal.offCanvas.isOffCanvas($element)) {
+      $('.is-layout-builder-highlighted').removeClass('is-layout-builder-highlighted');
+
+      var id = $element.find('[data-layout-builder-target-highlight-id]').attr('data-layout-builder-target-highlight-id');
+      if (id) {
+        $('[data-layout-builder-highlight-id="' + id + '"]').addClass('is-layout-builder-highlighted');
+      }
+    }
+  });
+
+  if (document.querySelector('[data-off-canvas-main-canvas]')) {
+    var mainCanvas = document.querySelector('[data-off-canvas-main-canvas]');
+
+    mainCanvas.addEventListener('transitionend', function () {
+      var $target = $('.is-layout-builder-highlighted');
+
+      if ($target.length > 0) {
+        var targetTop = $target.offset().top;
+        var targetBottom = targetTop + $target.outerHeight();
+        var viewportTop = $(window).scrollTop();
+        var viewportBottom = viewportTop + $(window).height();
+
+        if (targetBottom < viewportTop || targetTop > viewportBottom) {
+          var viewportMiddle = (viewportBottom + viewportTop) / 2;
+          var scrollAmount = targetTop - viewportMiddle;
+
+          if ('scrollBehavior' in document.documentElement.style) {
+            window.scrollBy({
+              top: scrollAmount,
+              left: 0,
+              behavior: 'smooth'
+            });
+          } else {
+            window.scrollBy(0, scrollAmount);
+          }
+        }
+      }
+    });
+  }
+
+  $(window).on('dialog:afterclose', function (event, dialog, $element) {
+    if (Drupal.offCanvas.isOffCanvas($element)) {
+      $('.is-layout-builder-highlighted').removeClass('is-layout-builder-highlighted');
+    }
+  });
 })(jQuery, Drupal);
\ No newline at end of file
diff --git a/core/modules/layout_builder/src/Controller/ChooseBlockController.php b/core/modules/layout_builder/src/Controller/ChooseBlockController.php
index ea721b7717fe7ec6f3db53a21d48edc4be2fa992..af9a3b3c2105410211abfd750abcf19aaa5d53ec 100644
--- a/core/modules/layout_builder/src/Controller/ChooseBlockController.php
+++ b/core/modules/layout_builder/src/Controller/ChooseBlockController.php
@@ -9,6 +9,7 @@
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
 use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
+use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -21,6 +22,7 @@ class ChooseBlockController implements ContainerInjectionInterface {
 
   use AjaxHelperTrait;
   use LayoutBuilderContextTrait;
+  use LayoutBuilderHighlightTrait;
   use StringTranslationTrait;
 
   /**
@@ -124,6 +126,7 @@ public function build(SectionStorageInterface $section_storage, $delta, $region)
     $block_categories['#type'] = 'container';
     $block_categories['#attributes']['class'][] = 'block-categories';
     $block_categories['#attributes']['class'][] = 'js-layout-builder-categories';
+    $block_categories['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockAddHighlightId($delta, $region);
 
     // @todo Explicitly cast delta to an integer, remove this in
     //   https://www.drupal.org/project/drupal/issues/2984509.
@@ -188,6 +191,7 @@ public function inlineBlockList(SectionStorageInterface $section_storage, $delta
         '#attributes' => $this->getAjaxAttributes(),
       ];
     }
+    $build['links']['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockAddHighlightId($delta, $region);
     return $build;
   }
 
diff --git a/core/modules/layout_builder/src/Controller/ChooseSectionController.php b/core/modules/layout_builder/src/Controller/ChooseSectionController.php
index f7c19c2118e3b97022513d734aa6d88fbee8455a..714c4770f82870f62d8c9afb027207f8a2fcdf36 100644
--- a/core/modules/layout_builder/src/Controller/ChooseSectionController.php
+++ b/core/modules/layout_builder/src/Controller/ChooseSectionController.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
+use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -19,6 +20,7 @@
 class ChooseSectionController implements ContainerInjectionInterface {
 
   use AjaxHelperTrait;
+  use LayoutBuilderHighlightTrait;
   use StringTranslationTrait;
 
   /**
@@ -96,6 +98,7 @@ public function build(SectionStorageInterface $section_storage, $delta) {
         'class' => [
           'layout-selection',
         ],
+        'data-layout-builder-target-highlight-id' => $this->sectionAddHighlightId($delta),
       ],
     ];
 
diff --git a/core/modules/layout_builder/src/Element/LayoutBuilder.php b/core/modules/layout_builder/src/Element/LayoutBuilder.php
index e53819611af132df6b8784ba7f871d02fdc54c05..9c98847e8907662e3d5b274c3ec5ad2c386493a4 100644
--- a/core/modules/layout_builder/src/Element/LayoutBuilder.php
+++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Render\Element\RenderElement;
 use Drupal\Core\Url;
 use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
+use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\OverridesSectionStorageInterface;
 use Drupal\layout_builder\SectionStorageInterface;
@@ -24,6 +25,7 @@ class LayoutBuilder extends RenderElement implements ContainerFactoryPluginInter
 
   use AjaxHelperTrait;
   use LayoutBuilderContextTrait;
+  use LayoutBuilderHighlightTrait;
 
   /**
    * The layout tempstore repository.
@@ -212,6 +214,7 @@ protected function buildAddSectionLink(SectionStorageInterface $section_storage,
       '#type' => 'container',
       '#attributes' => [
         'class' => ['layout-builder__add-section'],
+        'data-layout-builder-highlight-id' => $this->sectionAddHighlightId($delta),
       ],
     ];
   }
@@ -242,6 +245,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
         foreach (Element::children($build[$region]) as $uuid) {
           $build[$region][$uuid]['#attributes']['class'][] = 'draggable';
           $build[$region][$uuid]['#attributes']['data-layout-block-uuid'] = $uuid;
+          $build[$region][$uuid]['#attributes']['data-layout-builder-highlight-id'] = $this->blockUpdateHighlightId($uuid);
           $build[$region][$uuid]['#contextual_links'] = [
             'layout_builder_block' => [
               'route_parameters' => [
@@ -281,7 +285,10 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
         ),
       ];
       $build[$region]['layout_builder_add_block']['#type'] = 'container';
-      $build[$region]['layout_builder_add_block']['#attributes'] = ['class' => ['layout-builder__add-block']];
+      $build[$region]['layout_builder_add_block']['#attributes'] = [
+        'class' => ['layout-builder__add-block'],
+        'data-layout-builder-highlight-id' => $this->blockAddHighlightId($delta, $region),
+      ];
       $build[$region]['layout_builder_add_block']['#weight'] = 1000;
       $build[$region]['#attributes']['data-region'] = $region;
       $build[$region]['#attributes']['class'][] = 'layout-builder__region';
@@ -296,8 +303,10 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
       'section_storage_type' => $storage_type,
       'section_storage' => $storage_id,
     ])->toString();
+
     $build['#attributes']['data-layout-delta'] = $delta;
     $build['#attributes']['class'][] = 'layout-builder__layout';
+    $build['#attributes']['data-layout-builder-highlight-id'] = $this->sectionUpdateHighlightId($delta);
 
     return [
       '#type' => 'container',
diff --git a/core/modules/layout_builder/src/Form/AddBlockForm.php b/core/modules/layout_builder/src/Form/AddBlockForm.php
index 1d873308a1f2f5571db6ab2c65f6d688fd3f879a..ccfea97e2fcd742b1e8bb1dece9d7a95114d0577 100644
--- a/core/modules/layout_builder/src/Form/AddBlockForm.php
+++ b/core/modules/layout_builder/src/Form/AddBlockForm.php
@@ -3,6 +3,7 @@
 namespace Drupal\layout_builder\Form;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\SectionComponent;
 use Drupal\layout_builder\SectionStorageInterface;
 
@@ -13,6 +14,8 @@
  */
 class AddBlockForm extends ConfigureBlockFormBase {
 
+  use LayoutBuilderHighlightTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -53,6 +56,7 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
       $section_storage->getSection($delta)->appendComponent($component);
       $form_state->set('layout_builder__component', $component);
     }
+    $form['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockAddHighlightId($delta, $region);
     return $this->doBuildForm($form, $form_state, $section_storage, $delta, $component);
   }
 
diff --git a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
index 92584b58935ffd34253dfe017ad0cd780021c9ce..82fce6156b2f09e454af29c8c505c253edc72700 100644
--- a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
+++ b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\Plugin\PluginWithFormsInterface;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
+use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\Section;
 use Drupal\layout_builder\SectionStorageInterface;
@@ -24,6 +25,7 @@
 class ConfigureSectionForm extends FormBase {
 
   use AjaxFormHelperTrait;
+  use LayoutBuilderHighlightTrait;
   use LayoutRebuildTrait;
 
   /**
@@ -127,6 +129,8 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     if ($this->isAjax()) {
       $form['actions']['submit']['#ajax']['callback'] = '::ajaxSubmit';
     }
+    $target_highlight_id = $this->isUpdate ? $this->sectionUpdateHighlightId($delta) : $this->sectionAddHighlightId($delta);
+    $form['#attributes']['data-layout-builder-target-highlight-id'] = $target_highlight_id;
 
     return $form;
   }
diff --git a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
index d6c05f87bf1226ce061c8fc1c15eca51110c9dc4..06f09ae9b703736bbaf6107c9d6701534b0cea34 100644
--- a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
+++ b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
+use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -18,6 +19,7 @@
 abstract class LayoutRebuildConfirmFormBase extends ConfirmFormBase {
 
   use AjaxFormHelperTrait;
+  use LayoutBuilderHighlightTrait;
   use LayoutRebuildTrait;
 
   /**
@@ -79,6 +81,8 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     if ($this->isAjax()) {
       $form['actions']['submit']['#ajax']['callback'] = '::ajaxSubmit';
       $form['actions']['cancel']['#attributes']['class'][] = 'dialog-cancel';
+      $target_highlight_id = !empty($this->uuid) ? $this->blockUpdateHighlightId($this->uuid) : $this->sectionUpdateHighlightId($delta);
+      $form['#attributes']['data-layout-builder-target-highlight-id'] = $target_highlight_id;
     }
 
     return $form;
diff --git a/core/modules/layout_builder/src/Form/UpdateBlockForm.php b/core/modules/layout_builder/src/Form/UpdateBlockForm.php
index c00b406eb2cb2a5e666410fd185ad408cf2659cd..59cf91fd56a284ca4d61cf68952b8ef20f63ef4e 100644
--- a/core/modules/layout_builder/src/Form/UpdateBlockForm.php
+++ b/core/modules/layout_builder/src/Form/UpdateBlockForm.php
@@ -3,6 +3,7 @@
 namespace Drupal\layout_builder\Form;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\SectionStorageInterface;
 
 /**
@@ -12,6 +13,8 @@
  */
 class UpdateBlockForm extends ConfigureBlockFormBase {
 
+  use LayoutBuilderHighlightTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -40,6 +43,7 @@ public function getFormId() {
    */
   public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, $delta = NULL, $region = NULL, $uuid = NULL) {
     $component = $section_storage->getSection($delta)->getComponent($uuid);
+    $form['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockUpdateHighlightId($uuid);
     return $this->doBuildForm($form, $form_state, $section_storage, $delta, $component);
   }
 
diff --git a/core/modules/layout_builder/src/LayoutBuilderHighlightTrait.php b/core/modules/layout_builder/src/LayoutBuilderHighlightTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..5c3e53c7b5546fce5c21c31f3b1836566253a7ff
--- /dev/null
+++ b/core/modules/layout_builder/src/LayoutBuilderHighlightTrait.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Drupal\layout_builder;
+
+/**
+ * A trait for generating IDs used to highlight active UI elements.
+ */
+trait LayoutBuilderHighlightTrait {
+
+  /**
+   * Provides the ID used to highlight the active Layout Builder UI element.
+   *
+   * @param string $delta
+   *   The section the block is in.
+   * @param string $region
+   *   The section region in which the block is placed.
+   *
+   * @return string
+   *   The highlight ID of the block.
+   */
+  protected function blockAddHighlightId($delta, $region) {
+    return "block-$delta-$region";
+  }
+
+  /**
+   * Provides the ID used to highlight the active Layout Builder UI element.
+   *
+   * @param string $uuid
+   *   The uuid of the block.
+   *
+   * @return string
+   *   The highlight ID of the block.
+   */
+  protected function blockUpdateHighlightId($uuid) {
+    return $uuid;
+  }
+
+  /**
+   * Provides the ID used to highlight the active Layout Builder UI element.
+   *
+   * @param string $delta
+   *   The location of the section.
+   *
+   * @return string
+   *   The highlight ID of the section.
+   */
+  protected function sectionAddHighlightId($delta) {
+    return "section-$delta";
+  }
+
+  /**
+   * Provides the ID used to highlight the active Layout Builder UI element.
+   *
+   * @param string $delta
+   *   The location of the section.
+   *
+   * @return string
+   *   The highlight ID of the section.
+   */
+  protected function sectionUpdateHighlightId($delta) {
+    return "section-update-$delta";
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php
index e4b342ba86ca0beac96057b94adc599a58244521..b7168a6610a2e30da24cb845bd7efad6c4302468 100644
--- a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php
@@ -231,19 +231,20 @@ protected function assertContextualLinksClickable() {
   protected function assertContextualLinkRetainsMouseup() {
     $assert_session = $this->assertSession();
     $page = $this->getSession()->getPage();
+    $body_field_selector = '.block-field-blocknodebundle-with-section-fieldbody';
 
-    $body_block = $page->find('css', '.block-field-blocknodebundle-with-section-fieldbody');
+    $body_block = $page->find('css', $body_field_selector);
     $this->assertNotEmpty($body_block);
 
     // Get the current Y position of the body block.
-    $body_block_y_position = $this->getSession()->evaluateScript("document.getElementsByClassName('block-field-blocknodebundle-with-section-fieldbody')[0].getBoundingClientRect().top + window.pageYOffset");
+    $body_block_top_position = $this->getElementVerticalPosition($body_field_selector, 'top');
 
     $body_block_contextual_link_button = $body_block->find('css', '.trigger');
     $this->assertNotEmpty($body_block_contextual_link_button);
 
     // If the body block contextual link is hidden, make it visible.
     if ($body_block_contextual_link_button->hasClass('visually-hidden')) {
-      $this->toggleContextualTriggerVisibility('.block-field-blocknodebundle-with-section-fieldbody');
+      $this->toggleContextualTriggerVisibility($body_field_selector);
     }
 
     // For the purposes of this test, the contextual link must be accessed with
@@ -254,13 +255,41 @@ protected function assertContextualLinkRetainsMouseup() {
     $assert_session->assertWaitOnAjaxRequest();
 
     // After the contextual link opens the dialog, move the mouse pointer
-    // elsewhere on the page.
+    // elsewhere on the page. If mouse up were not working correctly this would
+    // actually drag the body field too.
     $this->movePointerTo('#iframe-that-should-be-disabled');
 
-    // If mouseup is working properly, the body block should be in the same
-    // position it was when $body_block_y_position was declared.
-    $new_body_block_y_position = $this->getSession()->evaluateScript("document.getElementsByClassName('block-field-blocknodebundle-with-section-fieldbody')[0].getBoundingClientRect().top + window.pageYOffset");
-    $this->assertEquals($body_block_y_position, $new_body_block_y_position);
+    $new_body_block_bottom_position = $this->getElementVerticalPosition($body_field_selector, 'bottom');
+    $iframe_top_position = $this->getElementVerticalPosition('#iframe-that-should-be-disabled', 'top');
+
+    $minimum_distance_mouse_moved = $iframe_top_position - $new_body_block_bottom_position;
+    $this->assertGreaterThan(200, $minimum_distance_mouse_moved, 'The mouse moved at least 200 pixels');
+
+    // If mouseup is working properly, the body block should be nearly in same
+    // position as it was when $body_block_y_position was declared. It will have
+    // moved slightly because the current block being configured will have a
+    // border that was not present when the dialog was not open.
+    $new_body_block_top_position = $this->getElementVerticalPosition($body_field_selector, 'top');
+    $distance_body_block_moved = abs($body_block_top_position - $new_body_block_top_position);
+    // Confirm that body moved only slightly compared to the distance the mouse
+    // moved and therefore was not dragged when the mouse moved.
+    $this->assertGreaterThan($distance_body_block_moved * 20, $minimum_distance_mouse_moved);
+  }
+
+  /**
+   * Gets the element position.
+   *
+   * @param string $css_selector
+   *   The CSS selector of the element.
+   * @param string $position_type
+   *   The position type to get, either 'top' or 'bottom'.
+   *
+   * @return int
+   *   The element position.
+   */
+  protected function getElementVerticalPosition($css_selector, $position_type) {
+    $this->assertTrue(in_array($position_type, ['top', 'bottom']), 'Expected position type.');
+    return (int) $this->getSession()->evaluateScript("document.querySelector('$css_selector').getBoundingClientRect().$position_type + window.pageYOffset");
   }
 
   /**
diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php
index 06b80e76a473c873ce6c743fd1d74f5d992faaa5..2b3ba8ebfcb96cb8134fce784e68ea8942a96621 100644
--- a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php
@@ -2,7 +2,9 @@
 
 namespace Drupal\Tests\layout_builder\FunctionalJavascript;
 
+use Drupal\block_content\Entity\BlockContentType;
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
 
 /**
  * Tests the Layout Builder UI.
@@ -11,6 +13,8 @@
  */
 class LayoutBuilderUiTest extends WebDriverTestBase {
 
+  use ContextualLinkClickTrait;
+
   /**
    * Path prefix for the field UI for the test bundle.
    *
@@ -22,6 +26,10 @@ class LayoutBuilderUiTest extends WebDriverTestBase {
     'layout_builder',
     'block',
     'node',
+    'block_content',
+    'contextual',
+    'views',
+    'layout_builder_test_css_transitions',
   ];
 
   /**
@@ -40,6 +48,7 @@ protected function setUp() {
       'configure any layout',
       'administer node display',
       'administer node fields',
+      'access contextual links',
     ]));
 
     // Enable layout builder.
@@ -116,4 +125,156 @@ protected function assertModifiedLayout($path) {
     $assert_session->pageTextContainsOnce('You have unsaved changes.');
   }
 
+  /**
+   * Tests that elements that open the dialog are properly highlighted.
+   */
+  public function testAddHighlights() {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+
+    $bundle = BlockContentType::create([
+      'id' => 'basic',
+      'label' => 'Basic block',
+      'revision' => 1,
+    ]);
+    $bundle->save();
+    block_content_add_body_field($bundle->id());
+
+    $this->drupalGet(static::FIELD_UI_PREFIX . '/display/default/layout');
+    $assert_session->elementsCount('css', '.layout-builder__add-section', 2);
+    $assert_session->elementNotExists('css', '.is-layout-builder-highlighted');
+    $page->clickLink('Add Section');
+    $this->assertNotEmpty($assert_session->waitForElement('css', '#drupal-off-canvas .item-list'));
+    $assert_session->assertWaitOnAjaxRequest();
+
+    // Highlight is present with AddSectionController.
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="section-0"]');
+    $page->clickLink('Two column');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas input[type="submit"][value="Add section"]'));
+    $assert_session->assertWaitOnAjaxRequest();
+
+    // The highlight is present with ConfigureSectionForm.
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="section-0"]');
+
+    // Submit the form to add the section and then confirm that no element is
+    // highlighted anymore.
+    $page->pressButton("Add section");
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertHighlightNotExists();
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '[data-layout-delta="1"]'));
+    $assert_session->elementsCount('css', '.layout-builder__add-block', 3);
+
+    // Add a custom block.
+    $page->clickLink('Add Block');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', 'a:contains("Create custom block")'));
+    $assert_session->assertWaitOnAjaxRequest();
+
+    // Highlight is present with ChooseBlockController::build().
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="block-0-first"]');
+    $page->clickLink('Create custom block');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas input[value="Add Block"]'));
+    $assert_session->assertWaitOnAjaxRequest();
+
+    // Highlight is present with ChooseBlockController::inlineBlockList().
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="block-0-first"]');
+    $page->pressButton('Close');
+    $this->assertHighlightNotExists();
+
+    // The highlight should persist with all block config dialogs.
+    $page->clickLink('Add Block');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', 'a:contains("Recent content")'));
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="block-0-first"]');
+    $page->clickLink('Recent content');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas input[value="Add Block"]'));
+
+    // The highlight is present with ConfigureBlockFormBase::doBuildForm().
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="block-0-first"]');
+    $page->pressButton('Close');
+    $this->assertHighlightNotExists();
+
+    // The highlight is present when the "Configure section" dialog is open.
+    $page->clickLink('Configure section');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="section-update-0"]');
+    $page->pressButton('Close');
+    $this->assertHighlightNotExists();
+
+    // The highlight is present when the "Remove section" dialog is open.
+    $page->clickLink('Remove section');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertHighlightedElement('[data-layout-builder-highlight-id="section-update-0"]');
+    $page->pressButton('Close');
+    $this->assertHighlightNotExists();
+
+    // A block is highlighted when its "Configure" contextual link is clicked.
+    $this->clickContextualLink('.block-field-blocknodebundle-with-section-fieldbody', 'Configure');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertHighlightedElement('.block-field-blocknodebundle-with-section-fieldbody');
+
+    // Make sure the highlight remains when contextual links are revealed with
+    // the mouse.
+    $this->toggleContextualTriggerVisibility('.block-field-blocknodebundle-with-section-fieldbody');
+    $active_section = $page->find('css', '.block-field-blocknodebundle-with-section-fieldbody');
+    $active_section->pressButton('Open configuration options');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '.block-field-blocknodebundle-with-section-fieldbody .contextual.open'));
+
+    $page->pressButton('Close');
+    $this->assertHighlightNotExists();
+
+    // @todo Remove the reload once https://www.drupal.org/node/2918718 is
+    //   completed.
+    $this->getSession()->reload();
+
+    // Block is highlighted when its "Remove block" contextual link is clicked.
+    $this->clickContextualLink('.block-field-blocknodebundle-with-section-fieldbody', 'Remove block');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertHighlightedElement('.block-field-blocknodebundle-with-section-fieldbody');
+    $page->pressButton('Close');
+    $this->assertHighlightNotExists();
+  }
+
+  /**
+   * Confirms the presence of the 'is-layout-builder-highlighted' class.
+   *
+   * @param string $selector
+   *   The highlighted element must also match this selector.
+   */
+  private function assertHighlightedElement($selector) {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+
+    // There is only one highlighted element.
+    $assert_session->elementsCount('css', '.is-layout-builder-highlighted', 1);
+
+    // The selector is also the highlighted element.
+    $this->assertTrue($page->find('css', $selector)->hasClass('is-layout-builder-highlighted'));
+  }
+
+  /**
+   * Waits for the dialog to close and confirms no highlights are present.
+   */
+  private function assertHighlightNotExists() {
+    $this->waitForNoElement('#drupal-off-canvas');
+    $this->waitForNoElement('.is-layout-builder-highlighted');
+  }
+
+  /**
+   * Waits for an element to be removed from the page.
+   *
+   * @param string $selector
+   *   CSS selector.
+   * @param int $timeout
+   *   (optional) Timeout in milliseconds, defaults to 10000.
+   *
+   * @todo Remove in https://www.drupal.org/node/2892440.
+   */
+  protected function waitForNoElement($selector, $timeout = 10000) {
+    $condition = "(typeof jQuery !== 'undefined' && jQuery('$selector').length === 0)";
+    $this->assertJsCondition($condition, $timeout);
+  }
+
 }