diff --git a/core/modules/outside_in/js/outside_in.js b/core/modules/outside_in/js/outside_in.js
index aa325b5..0f3b54f 100644
--- a/core/modules/outside_in/js/outside_in.js
+++ b/core/modules/outside_in/js/outside_in.js
@@ -7,32 +7,10 @@
 
   'use strict';
 
-  $('.outside-in-editable')
-    // Bind an event listener to the .outside-in-editable div
-    // This listen for click events and stops default actions of those elements.
-    .on('click', '.js-outside-in-edit-mode', function (e) {
-      if (localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false') {
-        e.preventDefault();
-      }
-    })
-    // Bind an event listener to the .outside-in-editable div
-    // When a click occurs try and find the outside-in edit link
-    // and click it.
-    .not('div.contextual a, div.contextual button')
-    .on('click', function (e) {
-      if ($(e.target.offsetParent).hasClass('contextual')) {
-        return;
-      }
-      if (!localStorage.getItem('Drupal.contextualToolbar.isViewing')) {
-        return;
-      }
-      var editLink = $(e.target).find('a[data-dialog-renderer="offcanvas"]')[0];
-      if (!editLink) {
-        var closest = $(e.target).closest('.outside-in-editable');
-        editLink = closest.find('li a[data-dialog-renderer="offcanvas"]')[0];
-      }
-      editLink.click();
-    });
+  var blockConfigureSelector = '[data-dialog-renderer="offcanvas"]';
+  var toggleEditSelector = '[data-drupal-outsidein="toggle"]';
+  var itemsToToggleSelector = '#main-canvas, #toolbar-bar, [data-drupal-outsidein="editable"] a, [data-drupal-outsidein="editable"] button';
+  var contextualItemsSelector = '[data-contextual-id] a, [data-contextual-id] button';
 
   /**
    * Reacts to contextual links being added.
@@ -53,45 +31,111 @@
     // Bind a listener to all 'Quick edit' links for blocks
     // Click "Edit" button in toolbar to force Contextual Edit which starts
     // Outside-In edit mode also.
-    data.$el.find('.outside-inblock-configure a').on('click', function () {
-      if (!isActiveMode()) {
-        $('div.contextual-toolbar-tab.toolbar-tab button').click();
-      }
-    });
+    data.$el.find(blockConfigureSelector)
+      .on('click.outsidein', function () {
+        if (!isInEditMode()) {
+          $(toggleEditSelector).trigger('click.outsidein');
+        }
+      });
   });
 
   /**
    * Gets all items that should be toggled with class during edit mode.
    *
-   * @return {*}
+   * @return {jQuery}
    *   Items that should be toggled.
    */
-  var getItemsToToggle = function () {
-    return $('#main-canvas, #toolbar-bar, .outside-in-editable a, .outside-in-editable button')
-      .not('div.contextual a, div.contextual button');
-  };
+  function getItemsToToggle() {
+    return $(itemsToToggleSelector).not(contextualItemsSelector);
+  }
 
-  var isActiveMode = function () {
+  /**
+   * Helper to check the state of the outside-in mode.
+   *
+   * @todo don't use a class for this.
+   *
+   * @return {bool}
+   *  State of the outside-in edit mode.
+   */
+  function isInEditMode() {
     return $('#toolbar-bar').hasClass('js-outside-in-edit-mode');
-  };
+  }
+
+  /**
+   * Helper to toggle Edit mode.
+   */
+  function toggleEditMode() {
+    setEditModeState(!isInEditMode());
+  }
+
+  /**
+   * Prevent default click events except contextual links.
+   *
+   * In edit mode the default action of click events is suppressed.
+   *
+   * @param {jQuery.Event} event
+   *   The click event.
+   */
+  function preventClick(event) {
+    // Do not prevent contextual links.
+    if ($(event.target).closest('.contextual-links').length) {
+      return;
+    }
+    event.preventDefault();
+  }
 
-  var setToggleActiveMode = function setToggleActiveMode(forceActive) {
-    forceActive = forceActive || false;
-    if (forceActive || !isActiveMode()) {
-      $('#toolbar-bar .contextual-toolbar-tab button').text(Drupal.t('Editing'));
+  /**
+   *  Helper to switch edit mode state.
+   *
+   * @param {bool} editMode
+   *  True enable edit mode, false disable edit mode.
+   */
+  function setEditModeState(editMode) {
+    editMode = !!editMode;
+    var $editButton = $(toggleEditSelector);
+    var $editables;
+    // Turn on edit mode.
+    if (editMode) {
+      $editButton.text(Drupal.t('Editing'));
       // Close the Manage tray if open when entering edit mode.
       if ($('#toolbar-item-administration-tray').hasClass('is-active')) {
-        $('#toolbar-item-administration').click();
+        $('#toolbar-item-administration').trigger('click');
+      }
+
+      $editables = $('[data-drupal-outsidein="editable"]').once('outsidein');
+      if ($editables.length) {
+        // Use event capture to prevent clicks on links.
+        document.querySelector('#main-canvas').addEventListener('click', preventClick, true);
+
+        // When a click occurs try and find the outside-in edit link
+        // and click it.
+        $editables
+          .not(contextualItemsSelector)
+          .on('click.outsidein', function (e) {
+            // Contextual links are allowed to function in Edit mode.
+            if ($(e.target).closest('.contextual').length || !localStorage.getItem('Drupal.contextualToolbar.isViewing')) {
+              return;
+            }
+
+            $(e.currentTarget).find(blockConfigureSelector).trigger('click');
+          });
       }
-      getItemsToToggle().addClass('js-outside-in-edit-mode');
-      $('.edit-mode-inactive').addClass('visually-hidden');
     }
+    // Disable edit mode.
     else {
-      $('#toolbar-bar .contextual-toolbar-tab button').text(Drupal.t('Edit'));
-      getItemsToToggle().removeClass('js-outside-in-edit-mode');
-      $('.edit-mode-inactive').removeClass('visually-hidden');
+      $editables = $('[data-drupal-outsidein="editable"]').removeOnce('outsidein');
+      if ($editables.length) {
+        document.querySelector('#main-canvas').removeEventListener('click', preventClick, true);
+        $editables.off('.outsidein');
+      }
+
+      $editButton.text(Drupal.t('Edit'));
+      // Close/remove offcanvas.
+      $('.ui-dialog-offcanvas .ui-dialog-titlebar-close').trigger('click');
     }
-  };
+    getItemsToToggle().toggleClass('js-outside-in-edit-mode', editMode);
+    $('.edit-mode-inactive').toggleClass('visually-hidden', editMode);
+  }
 
   /**
    * Attaches contextual's edit toolbar tab behavior.
@@ -105,7 +149,7 @@
     attach: function () {
       var editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
       if (editMode) {
-        setToggleActiveMode(true);
+        setEditModeState(true);
       }
     }
   };
@@ -118,11 +162,10 @@
    * @prop {Drupal~behaviorAttach} attach
    *   Toggle the js-outside-edit-mode class.
    */
-  Drupal.behaviors.toggleActiveMode = {
+  Drupal.behaviors.toggleEditMode = {
     attach: function () {
-      $('.contextual-toolbar-tab.toolbar-tab button').once('toggle-edit-mode').on('click', function () {
-        setToggleActiveMode();
-      });
+
+      $(toggleEditSelector).once('outsidein').on('click.outsidein', toggleEditMode);
 
       var search = Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog';
       var replace = Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog_offcanvas';
diff --git a/core/modules/outside_in/outside_in.libraries.yml b/core/modules/outside_in/outside_in.libraries.yml
index 0b704af..6728113 100644
--- a/core/modules/outside_in/outside_in.libraries.yml
+++ b/core/modules/outside_in/outside_in.libraries.yml
@@ -10,6 +10,7 @@ drupal.outside_in:
   dependencies:
     - core/jquery
     - core/drupal
+    - core/jquery.once
     - core/drupal.ajax
 drupal.off_canvas:
   version: VERSION
diff --git a/core/modules/outside_in/outside_in.module b/core/modules/outside_in/outside_in.module
index b3e6f07..d608ecd 100644
--- a/core/modules/outside_in/outside_in.module
+++ b/core/modules/outside_in/outside_in.module
@@ -89,8 +89,9 @@ function outside_in_preprocess_block(&$variables) {
   // The main system block does not contain the block contextual links.
   $variables['#cache']['contexts'][] = 'outside_in_is_applied';
   if ($variables['plugin_id'] !== 'system_main_block' && \Drupal::service('outside_in.manager')->isApplicable()) {
-    // Add class to all blocks to allow Javascript to target.
+    // Add class and attributes to all blocks to allow Javascript to target.
     $variables['attributes']['class'][] = 'outside-in-editable';
+    $variables['attributes']['data-drupal-outsidein'] = 'editable';
   }
 }
 
@@ -104,6 +105,7 @@ function outside_in_toolbar_alter(&$items) {
   if (isset($items['contextual']['tab']) && \Drupal::service('outside_in.manager')->isApplicable()) {
     $items['contextual']['#weight'] = -1000;
     $items['contextual']['#attached']['library'][] = 'outside_in/drupal.outside_in';
+    $items['contextual']['tab']['#attributes']['data-drupal-outsidein'] = 'toggle';
 
     // Set a class on items to mark whether they should be active in edit mode.
     // @todo Create a dynamic method for modules to set their own items.
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
index 4487e24..04d694d 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
@@ -12,7 +12,17 @@ class OutsideInBlockFormTest extends OutsideInJavascriptTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['block', 'system', 'breakpoint', 'toolbar', 'contextual', 'outside_in'];
+  public static $modules = [
+    'node',
+    'block',
+    'system',
+    'breakpoint',
+    'toolbar',
+    'contextual',
+    'outside_in',
+    'quickedit',
+    'search',
+  ];
 
   /**
    * {@inheritdoc}
@@ -26,72 +36,92 @@ protected function setUp() {
       'administer blocks',
       'access contextual links',
       'access toolbar',
+      'administer nodes',
+      'access in-place editing',
+      'search content',
     ]);
     $this->drupalLogin($user);
 
     $this->placeBlock('system_powered_by_block', ['id' => 'powered']);
     $this->placeBlock('system_branding_block', ['id' => 'branding']);
+    $this->placeBlock('search_form_block', ['id' => 'search']);
   }
 
   /**
-   * Tests updating the "Powered by Drupal" block in the Off-Canvas tray.
+   * Tests opening Offcanvas tray by click blocks and elements in the blocks.
    */
-  public function testPoweredByBlock() {
-
+  public function testBlocks() {
+    $blocks = [
+      [
+        'id' => 'block-powered',
+        'new_page_text' => 'Can you imagine anyone showing the label on this block?',
+        'element_selector' => '.content a',
+      ],
+      [
+        'id' => 'block-branding',
+        'new_page_text' => 'The site that will live a very short life.',
+        'element_selector' => 'a[rel="home"]:nth-child(2)',
+      ],
+      [
+        'id' => 'block-search',
+        'element_selector' => '#edit-submit',
+      ],
+    ];
     $page = $this->getSession()->getPage();
-    $web_assert = $this->assertSession();
-
-    $this->drupalGet('user');
-    $this->enableEditingMode();
-
-    // Open "Powered by Drupal" block form by clicking div.
-    $page->find('css', '#block-powered')->click();
-    $this->waitForOffCanvasToOpen();
-    $this->assertOffCanvasBlockFormIsValid();
-
-    // Fill out form, save the form.
-    $new_label = 'Can you imagine anyone showing the label on this block?';
-    $page->fillField('settings[label]', $new_label);
-    $page->checkField('settings[label_display]');
-
-    // @todo Uncomment the following lines after GastonJS problem solved.
-    // https://www.drupal.org/node/2789381
-    // $this->getTray()->pressButton('Save block');
-    // Make sure the changes are present.
-    // $web_assert->pageTextContains($new_label);
-  }
-
-  /**
-   * Tests updating the System Branding block in the Off-Canvas tray.
-   *
-   * Also tests updating the site name.
-   */
-  public function testBrandingBlock() {
-    $web_assert = $this->assertSession();
-    $this->drupalGet('user');
-    $page = $this->getSession()->getPage();
-    $this->enableEditingMode();
-
-    // Open branding block form by clicking div.
-    $page->find('css', '#block-branding')->click();
-    $this->waitForOffCanvasToOpen();
-    $this->assertOffCanvasBlockFormIsValid();
-
-    // Fill out form, save the form.
-    $new_site_name = 'The site that will live a very short life.';
-    $page->fillField('settings[site_information][site_name]', $new_site_name);
-
-    // @todo Uncomment the following lines after GastonJS problem solved.
-    // https://www.drupal.org/node/2789381
-    // $this->getTray()->pressButton('Save block');
-    // Make sure the changes are present.
-    //$web_assert->pageTextContains($new_site_name);
+    foreach ($blocks as $block) {
+      $block_selector = '#' . $block['id'];
+      $this->drupalGet('user');
+      $this->toggleEditingMode();
+      $this->openBlockForm($block_selector);
+
+      switch ($block['id']) {
+        case 'block-powered':
+          // Fill out form, save the form.
+          $page->fillField('settings[label]', $block['new_page_text']);
+          $page->checkField('settings[label_display]');
+          break;
+
+        case 'block-branding':
+          // Fill out form, save the form.
+          $page->fillField('settings[site_information][site_name]', $block['new_page_text']);
+          break;
+      }
+
+      if (isset($block['new_page_text'])) {
+        // @todo Use standard pressButton() after GastonJS problem solved.
+        // https://www.drupal.org/node/2789381
+        // $this->getTray()->pressButton('Save block');
+        $this->triggerClick('.ui-dialog-buttonset .js-form-submit');
+        // Make sure the changes are present.
+        $this->getSession()->wait(500);
+        $web_assert = $this->assertSession();
+        $web_assert->pageTextContains($block['new_page_text']);
+      }
+
+      $this->openBlockForm($block_selector);
+
+      $this->toggleEditingMode();
+      // Canvas should close when editing module is closed.
+      $this->waitForOffCanvasToClose();
+
+      // Go into Edit mode again.
+      $this->toggleEditingMode();
+
+      $element_selector = "$block_selector {$block['element_selector']}";
+      // Open block form by clicking a element inside the block.
+      // This confirms that default action for links and form elements is
+      // suppressed.
+      $this->openBlockForm($element_selector);
+
+      // Exit edit mode.
+      $this->toggleEditingMode();
+    }
   }
 
   /**
    * Enables Editing mode by pressing "Edit" button in the toolbar.
    */
-  protected function enableEditingMode() {
+  protected function toggleEditingMode() {
     $this->waitForElement('div[data-contextual-id="block:block=powered:langcode=en|outside_in::langcode=en"] .contextual-links a');
 
     $this->waitForElement('#toolbar-bar', 3000);
@@ -114,4 +144,29 @@ protected function assertOffCanvasBlockFormIsValid() {
     $web_assert->elementNotExists('css', 'select[data-drupal-selector="edit-region"]');
   }
 
+  /**
+   * Open block form by clicking the element found with a css selector.
+   *
+   * @param string $block_selector
+   *   A css selector selects the block or an element within it.
+   */
+  protected function openBlockForm($block_selector) {
+    $this->click($block_selector);
+    $this->waitForOffCanvasToOpen();
+    $this->assertOffCanvasBlockFormIsValid();
+  }
+
+  /**
+   * Trigger click on an element via Javascript.
+   *
+   * @todo Remove when Javascript testing bug is fixed. https://www.drupal.org/node/2773791
+   *
+   * @param string $css_selector
+   *   The CSS selector for the element to click.
+   */
+  protected function triggerClick($css_selector) {
+    $this->waitForElement($css_selector, 100);
+    $this->getSession()->getDriver()->evaluateScript("jQuery('$css_selector:first').click()");
+  }
+
 }
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
index bc9ff9a..4a33155 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
@@ -27,6 +27,8 @@ public function enableTheme($theme) {
    * Waits for Off-canvas tray to open.
    */
   protected function waitForOffCanvasToOpen() {
+    $web_assert = $this->assertSession();
+    $web_assert->assertWaitOnAjaxRequest();
     $this->waitForElement('#drupal-offcanvas');
   }
 
