diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index e645035613..4bdf5cb4be 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -903,3 +903,31 @@ underscore:
     gpl-compatible: true
   js:
     assets/vendor/underscore/underscore-min.js: { weight: -20, minified: true }
+
+drupal.dialog.off_canvas:
+  version: VERSION
+  js:
+    misc/dialog/off-canvas.js: {}
+  css:
+    base:
+      misc/dialog/off-canvas.reset.css: {}
+      misc/dialog/off-canvas.base.css: {}
+      misc/dialog/off-canvas.css: {}
+      # Add group setting to make sure this CSS load before any jQuery UI Dialog
+      # CSS.
+      misc/dialog/off-canvas.theme.css: { group: 200 }
+    component:
+      misc/dialog/off-canvas.motion.css: {}
+      misc/dialog/off-canvas.button.css: {}
+      misc/dialog/off-canvas.form.css: {}
+      misc/dialog/off-canvas.table.css: {}
+      misc/dialog/off-canvas.details.css: {}
+      misc/dialog/off-canvas.tabledrag.css: {}
+      misc/dialog/off-canvas.dropbutton.css: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
+    - core/drupal.ajax
+    - core/drupal.announce
+    - core/drupal.dialog
+    - core/drupal.dialog.ajax
diff --git a/core/core.services.yml b/core/core.services.yml
index 76088786cd..98996a6101 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1065,6 +1065,11 @@ services:
     arguments: ['@title_resolver']
     tags:
       - { name: render.main_content_renderer, format: drupal_dialog }
+  main_content_renderer.off_canvas:
+    class: Drupal\Core\Render\MainContent\OffCanvasRenderer
+    arguments: ['@title_resolver', '@renderer']
+    tags:
+      - { name: render.main_content_renderer, format: drupal_dialog.off_canvas }
   main_content_renderer.modal:
     class: Drupal\Core\Render\MainContent\ModalRenderer
     arguments: ['@title_resolver']
diff --git a/core/modules/outside_in/src/Ajax/OpenOffCanvasDialogCommand.php b/core/lib/Drupal/Core/Ajax/OpenOffCanvasDialogCommand.php
similarity index 96%
rename from core/modules/outside_in/src/Ajax/OpenOffCanvasDialogCommand.php
rename to core/lib/Drupal/Core/Ajax/OpenOffCanvasDialogCommand.php
index c5e2b2a5d1..da6a26e35a 100644
--- a/core/modules/outside_in/src/Ajax/OpenOffCanvasDialogCommand.php
+++ b/core/lib/Drupal/Core/Ajax/OpenOffCanvasDialogCommand.php
@@ -1,15 +1,11 @@
 <?php
 
-namespace Drupal\outside_in\Ajax;
-
-use Drupal\Core\Ajax\OpenDialogCommand;
+namespace Drupal\Core\Ajax;
 
 /**
  * Defines an AJAX command to open content in a dialog in a off-canvas dialog.
  *
  * @ingroup ajax
- *
- * @internal
  */
 class OpenOffCanvasDialogCommand extends OpenDialogCommand {
 
diff --git a/core/modules/outside_in/src/Render/MainContent/OffCanvasRenderer.php b/core/lib/Drupal/Core/Render/MainContent/OffCanvasRenderer.php
similarity index 89%
rename from core/modules/outside_in/src/Render/MainContent/OffCanvasRenderer.php
rename to core/lib/Drupal/Core/Render/MainContent/OffCanvasRenderer.php
index 8bcaa578d4..55bf8eb7d1 100644
--- a/core/modules/outside_in/src/Render/MainContent/OffCanvasRenderer.php
+++ b/core/lib/Drupal/Core/Render/MainContent/OffCanvasRenderer.php
@@ -1,13 +1,12 @@
 <?php
 
-namespace Drupal\outside_in\Render\MainContent;
+namespace Drupal\Core\Render\MainContent;
 
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Controller\TitleResolverInterface;
-use Drupal\Core\Render\MainContent\DialogRenderer;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\outside_in\Ajax\OpenOffCanvasDialogCommand;
+use Drupal\Core\Ajax\OpenOffCanvasDialogCommand;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -47,7 +46,7 @@ public function renderResponse(array $main_content, Request $request, RouteMatch
     $content = $this->renderer->renderRoot($main_content);
     // Attach the library necessary for using the OpenOffCanvasDialogCommand and
     // set the attachments for this Ajax response.
-    $main_content['#attached']['library'][] = 'outside_in/drupal.off_canvas';
+    $main_content['#attached']['library'][] = 'core/drupal.dialog.off_canvas';
     $response->setAttachments($main_content['#attached']);
 
     // If the main content doesn't provide a title, use the title resolver.
diff --git a/core/modules/outside_in/css/off-canvas.base.css b/core/misc/dialog/off-canvas.base.css
similarity index 95%
copy from core/modules/outside_in/css/off-canvas.base.css
copy to core/misc/dialog/off-canvas.base.css
index aaa713dbbe..a0cb456983 100644
--- a/core/modules/outside_in/css/off-canvas.base.css
+++ b/core/misc/dialog/off-canvas.base.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Set base styles for the settings tray.
+ * Set base styles for the off-canvas dialog.
  */
 
 /* Set some global attributes. */
@@ -217,18 +217,18 @@
 }
 #drupal-off-canvas .messages--status {
   background-color: #f3faef;
-  background-image: url(../../../misc/icons/73b355/check.svg);
+  background-image: url(../icons/73b355/check.svg);
   color: #325e1c;
 }
 #drupal-off-canvas .messages--warning {
   background-color: #fdf8ed;
-  background-image: url(../../../misc/icons/e29700/warning.svg);
+  background-image: url(../icons/e29700/warning.svg);
   color: #734c00;
 }
 
 #drupal-off-canvas .messages--error {
   background-color: #fcf4f2;
-  background-image: url(../../../misc/icons/e32700/error.svg);
+  background-image: url(../icons/e32700/error.svg);
   color: #a51b00;
 }
 
diff --git a/core/modules/outside_in/css/off-canvas.button.css b/core/misc/dialog/off-canvas.button.css
similarity index 96%
copy from core/modules/outside_in/css/off-canvas.button.css
copy to core/misc/dialog/off-canvas.button.css
index 2b734f8a81..1f8ed5537d 100644
--- a/core/modules/outside_in/css/off-canvas.button.css
+++ b/core/misc/dialog/off-canvas.button.css
@@ -1,8 +1,8 @@
 /**
  * @file
- * Visual styling for buttons in the off canvas tray.
+ * Visual styling for buttons in the off-canvas dialog.
  *
- * See seven/css/components/buttons.css
+ * @see seven/css/components/buttons.css
  */
 
 #drupal-off-canvas button,
diff --git a/core/modules/outside_in/css/off-canvas.css b/core/misc/dialog/off-canvas.css
similarity index 69%
copy from core/modules/outside_in/css/off-canvas.css
copy to core/misc/dialog/off-canvas.css
index d7f3258b26..52a8b9e079 100644
--- a/core/modules/outside_in/css/off-canvas.css
+++ b/core/misc/dialog/off-canvas.css
@@ -1,8 +1,6 @@
 /**
  * @file
  * CSS for off-canvas dialog.
- *
- * @todo Move CSS into core dialog library https://www.drupal.org/node/2784443.
  */
 
 /* Position the off-canvas dialog container outside the right of the viewport. */
@@ -23,14 +21,14 @@
   text-align: right;
 }
 
-/* Position the dialog-off-canvas tray container outside the right of the viewport. */
+/* Position the off-canvas dialog container outside the right of the viewport. */
 .ui-dialog-off-canvas {
   box-sizing: border-box;
   height: 100%;
   overflow: visible;
 }
 
-/* Wrap the form that's inside the dialog-off-canvas tray. */
+/* Wrap the form that's inside the off-canvas dialog. */
 .ui-dialog-off-canvas #drupal-off-canvas {
   padding: 0 20px;
   /* Prevent horizontal scrollbar. */
@@ -42,15 +40,15 @@
 }
 
 /*
- * Force the tray to be 100% width at the same breakpoint the dialog system uses
- * to expand dialog widths.
+ * Force the off-canvas dialog to be 100% width at the same breakpoint the
+ * dialog system uses to expand dialog widths.
  */
 @media all and (max-width: 48em) { /* 768px */
   .ui-dialog.ui-dialog-off-canvas {
     width: 100% !important;
   }
-  /* When tray is at 100% width stop the body from scrolling */
-  .js-tray-open {
+  /* When off-canvas dialog is at 100% width stop the body from scrolling */
+  .js-off-canvas-dialog-open {
     height: 100%;
     overflow-y: hidden;
   }
diff --git a/core/modules/outside_in/css/off-canvas.details.css b/core/misc/dialog/off-canvas.details.css
similarity index 93%
copy from core/modules/outside_in/css/off-canvas.details.css
copy to core/misc/dialog/off-canvas.details.css
index dcac6a5b04..fcd526f0b0 100644
--- a/core/modules/outside_in/css/off-canvas.details.css
+++ b/core/misc/dialog/off-canvas.details.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Visual styling for summary and details in the Settings Tray module's off canvas tray.
+ * Visual styling for summary and details in the off-canvas dialog.
  */
 
 #drupal-off-canvas details,
diff --git a/core/modules/outside_in/css/off-canvas.dropbutton.css b/core/misc/dialog/off-canvas.dropbutton.css
similarity index 98%
copy from core/modules/outside_in/css/off-canvas.dropbutton.css
copy to core/misc/dialog/off-canvas.dropbutton.css
index e467a4f341..7211dceaf5 100644
--- a/core/modules/outside_in/css/off-canvas.dropbutton.css
+++ b/core/misc/dialog/off-canvas.dropbutton.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Styles for dropbuttons in the off-canvas tray.
+ * Styles for dropbuttons in the off-canvas dialog.
  */
 
 #drupal-off-canvas .dropbutton-wrapper,
@@ -241,7 +241,7 @@
   content: '.';
   display: block;
   color: transparent;
-  background: transparent url(../../../misc/icons/ffffff/pencil.svg) no-repeat center;
+  background: transparent url(../icons/ffffff/pencil.svg) no-repeat center;
   background-size: 14px;
 }
 
diff --git a/core/misc/dialog/off-canvas.es6.js b/core/misc/dialog/off-canvas.es6.js
new file mode 100644
index 0000000000..c8e4599f6e
--- /dev/null
+++ b/core/misc/dialog/off-canvas.es6.js
@@ -0,0 +1,260 @@
+/**
+ * @file
+ * Drupal's off-canvas library.
+ */
+
+(($, Drupal, debounce, displace) => {
+  /**
+   * Off-canvas dialog implementation using jQuery Dialog.
+   *
+   * Transforms the regular dialogs created using Drupal.dialog when the dialog
+   * element equals '#drupal-off-canvas' into an side-loading dialog.
+   *
+   * @namespace
+   */
+  Drupal.offCanvas = {
+
+    /**
+     * The minimum width to use body displace needs to match the width at which
+     * the tray will be 100% width. @see core/misc/dialog/off-canvas.css
+     *
+     * @type {Number}
+     */
+    minDisplaceWidth: 768,
+
+    /**
+     * Wrapper used to position off-canvas dialog.
+     *
+     * @type {jQuery}
+     */
+    $mainCanvasWrapper: $('[data-off-canvas-main-canvas]'),
+
+    /**
+     * Determines if an element is an off-canvas dialog.
+     *
+     * @param {jQuery} $element
+     *   The dialog element.
+     *
+     * @return {bool}
+     *   True this is currently an off-canvas dialog.
+     */
+    isOffCanvas($element) {
+      return $element.is('#drupal-off-canvas');
+    },
+
+    /**
+     * Handler fired before an off-canvas dialog has been opened.
+     *
+     * @param {Object} settings
+     *   Settings related to the composition of the dialog.
+     *
+     * @return {undefined}
+     */
+    beforeCreate({ settings }) {
+      $('body').addClass('js-off-canvas-dialog-open');
+      // @see http://api.jqueryui.com/position/
+      settings.position = {
+        my: 'left top',
+        at: `${Drupal.offCanvas.getEdge()} top`,
+        of: window,
+      };
+
+      /**
+       * Applies initial height to dialog based on window height.
+       * @see http://api.jqueryui.com/dialog for all dialog options.
+       */
+      settings.height = $(window).height();
+    },
+
+    /**
+     * Handler fired after an off-canvas dialog has been closed.
+     *
+     * @return {undefined}
+     */
+    beforeClose() {
+      $('body').removeClass('js-off-canvas-dialog-open');
+      // Remove all *.off-canvas events
+      $(document).off('.off-canvas');
+      $(window).off('.off-canvas');
+      Drupal.offCanvas.$mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`, 0);
+    },
+
+    /**
+     * Handler fired when an off-canvas dialog has been opened.
+     *
+     * @param {jQuery} $element
+     *   The off-canvas dialog element.
+     * @param {Object} settings
+     *   Settings related to the composition of the dialog.
+     *
+     * @return {undefined}
+     */
+    afterCreate({ $element, settings }) {
+      const eventData = { settings, $element, offCanvasDialog: this };
+
+      $element
+        .on('dialogresize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100))
+        .on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.handleDialogResize)
+        .on('dialogContentResize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100))
+        .trigger('dialogresize.off-canvas');
+
+      Drupal.offCanvas.getContainer($element).attr(`data-offset-${Drupal.offCanvas.getEdge()}`, '');
+
+      $(window)
+        .on('resize.off-canvas scroll.off-canvas', eventData, debounce(Drupal.offCanvas.resetSize, 100))
+        .trigger('resize.off-canvas');
+    },
+
+    /**
+     * Toggle classes based on title existence.
+     * Called with Drupal.offCanvas.afterCreate.
+     *
+     * @param {Object} settings
+     *   Settings related to the composition of the dialog.
+     *
+     * @return {undefined}
+     */
+    render({ settings }) {
+      $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title);
+    },
+
+    /**
+     * Adjusts the dialog on resize.
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered.
+     * @param {object} event.data
+     *   Data attached to the event.
+     */
+    handleDialogResize(event) {
+      const $element = event.data.$element;
+      const $container = Drupal.offCanvas.getContainer($element);
+
+      const $offsets = $container.find('> :not(#drupal-off-canvas, .ui-resizable-handle)');
+      let offset = 0;
+
+      // Let scroll element take all the height available.
+      $element.css({ height: 'auto' });
+      const modalHeight = $container.height();
+
+      $offsets.each((i, e) => {
+        offset += $(e).outerHeight();
+      });
+
+      // Take internal padding into account.
+      const scrollOffset = $element.outerHeight() - $element.height();
+      $element.height(modalHeight - offset - scrollOffset);
+    },
+
+    /**
+     * Resets the size of the dialog.
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered.
+     * @param {object} event.data
+     *   Data attached to the event.
+     */
+    resetSize(event) {
+      const offsets = displace.offsets;
+      const $element = event.data.$element;
+      const container = Drupal.offCanvas.getContainer($element);
+
+      const topPosition = (offsets.top !== 0 ? `+${offsets.top}` : '');
+      const adjustedOptions = {
+        // @see http://api.jqueryui.com/position/
+        position: {
+          my: `${Drupal.offCanvas.getEdge()} top`,
+          at: `${Drupal.offCanvas.getEdge()} top${topPosition}`,
+          of: window,
+        },
+      };
+
+      container.css({
+        position: 'fixed',
+        height: `${$(window).height() - (offsets.top + offsets.bottom)}px`,
+      });
+
+      $element
+        .dialog('option', adjustedOptions)
+        .trigger('dialogContentResize.off-canvas');
+    },
+
+    /**
+     * Adjusts the body padding when the dialog is resized.
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered.
+     * @param {object} event.data
+     *   Data attached to the event.
+     */
+    bodyPadding(event) {
+      if ($('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth) {
+        return;
+      }
+      const $element = event.data.$element;
+      const $container = Drupal.offCanvas.getContainer($element);
+      const $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper;
+
+      const width = $container.outerWidth();
+      const mainCanvasPadding = $mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`);
+      if (width !== mainCanvasPadding) {
+        $mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`, `${width}px`);
+        $container.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, width);
+        displace();
+      }
+    },
+
+    /**
+     * The HTML element that surrounds the dialog.
+     * @param {HTMLElement} $element
+     *   The dialog element.
+     *
+     * @return {HTMLElement}
+     *   The containing element.
+     */
+    getContainer($element) {
+      return $element.dialog('widget');
+    },
+
+    /**
+     * The edge of the screen that the dialog should appear on.
+     *
+     * @return {string}
+     *   The edge the tray will be shown on, left or right.
+     */
+    getEdge() {
+      return document.documentElement.dir === 'rtl' ? 'left' : 'right';
+    },
+  };
+
+  /**
+   * Attaches off-canvas dialog behaviors.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches event listeners for off-canvas dialogs.
+   */
+  Drupal.behaviors.offCanvasEvents = {
+    attach: () => {
+      $(window).once('off-canvas').on({
+        'dialog:beforecreate': (event, dialog, $element, settings) => {
+          if (Drupal.offCanvas.isOffCanvas($element)) {
+            Drupal.offCanvas.beforeCreate({ dialog, $element, settings });
+          }
+        },
+        'dialog:aftercreate': (event, dialog, $element, settings) => {
+          if (Drupal.offCanvas.isOffCanvas($element)) {
+            Drupal.offCanvas.render({ dialog, $element, settings });
+            Drupal.offCanvas.afterCreate({ $element, settings });
+          }
+        },
+        'dialog:beforeclose': (event, dialog, $element) => {
+          if (Drupal.offCanvas.isOffCanvas($element)) {
+            Drupal.offCanvas.beforeClose({ dialog, $element });
+          }
+        },
+      });
+    },
+  };
+})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
diff --git a/core/modules/outside_in/css/off-canvas.form.css b/core/misc/dialog/off-canvas.form.css
similarity index 97%
copy from core/modules/outside_in/css/off-canvas.form.css
copy to core/misc/dialog/off-canvas.form.css
index 254b2c74e9..ac3189bf39 100644
--- a/core/modules/outside_in/css/off-canvas.form.css
+++ b/core/misc/dialog/off-canvas.form.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Visual styling for forms in the Settings Tray module's off canvas tray.
+ * Visual styling for forms in the off-canvas dialog.
  */
 
 #drupal-off-canvas form {
@@ -131,6 +131,5 @@
 }
 #drupal-off-canvas .ui-autocomplete li a {
   color: #595959 !important;
-  cursor: pointer;
   padding: 5px;
 }
diff --git a/core/misc/dialog/off-canvas.js b/core/misc/dialog/off-canvas.js
new file mode 100644
index 0000000000..83ce5565ff
--- /dev/null
+++ b/core/misc/dialog/off-canvas.js
@@ -0,0 +1,138 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function ($, Drupal, debounce, displace) {
+  Drupal.offCanvas = {
+    minDisplaceWidth: 768,
+
+    $mainCanvasWrapper: $('[data-off-canvas-main-canvas]'),
+
+    isOffCanvas: function isOffCanvas($element) {
+      return $element.is('#drupal-off-canvas');
+    },
+    beforeCreate: function beforeCreate(_ref) {
+      var settings = _ref.settings;
+
+      $('body').addClass('js-off-canvas-dialog-open');
+
+      settings.position = {
+        my: 'left top',
+        at: Drupal.offCanvas.getEdge() + ' top',
+        of: window
+      };
+
+      settings.height = $(window).height();
+    },
+    beforeClose: function beforeClose() {
+      $('body').removeClass('js-off-canvas-dialog-open');
+
+      $(document).off('.off-canvas');
+      $(window).off('.off-canvas');
+      Drupal.offCanvas.$mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge(), 0);
+    },
+    afterCreate: function afterCreate(_ref2) {
+      var $element = _ref2.$element,
+          settings = _ref2.settings;
+
+      var eventData = { settings: settings, $element: $element, offCanvasDialog: this };
+
+      $element.on('dialogresize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100)).on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.handleDialogResize).on('dialogContentResize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100)).trigger('dialogresize.off-canvas');
+
+      Drupal.offCanvas.getContainer($element).attr('data-offset-' + Drupal.offCanvas.getEdge(), '');
+
+      $(window).on('resize.off-canvas scroll.off-canvas', eventData, debounce(Drupal.offCanvas.resetSize, 100)).trigger('resize.off-canvas');
+    },
+    render: function render(_ref3) {
+      var settings = _ref3.settings;
+
+      $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title);
+    },
+    handleDialogResize: function handleDialogResize(event) {
+      var $element = event.data.$element;
+      var $container = Drupal.offCanvas.getContainer($element);
+
+      var $offsets = $container.find('> :not(#drupal-off-canvas, .ui-resizable-handle)');
+      var offset = 0;
+
+      $element.css({ height: 'auto' });
+      var modalHeight = $container.height();
+
+      $offsets.each(function (i, e) {
+        offset += $(e).outerHeight();
+      });
+
+      var scrollOffset = $element.outerHeight() - $element.height();
+      $element.height(modalHeight - offset - scrollOffset);
+    },
+    resetSize: function resetSize(event) {
+      var offsets = displace.offsets;
+      var $element = event.data.$element;
+      var container = Drupal.offCanvas.getContainer($element);
+
+      var topPosition = offsets.top !== 0 ? '+' + offsets.top : '';
+      var adjustedOptions = {
+        position: {
+          my: Drupal.offCanvas.getEdge() + ' top',
+          at: Drupal.offCanvas.getEdge() + ' top' + topPosition,
+          of: window
+        }
+      };
+
+      container.css({
+        position: 'fixed',
+        height: $(window).height() - (offsets.top + offsets.bottom) + 'px'
+      });
+
+      $element.dialog('option', adjustedOptions).trigger('dialogContentResize.off-canvas');
+    },
+    bodyPadding: function bodyPadding(event) {
+      if ($('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth) {
+        return;
+      }
+      var $element = event.data.$element;
+      var $container = Drupal.offCanvas.getContainer($element);
+      var $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper;
+
+      var width = $container.outerWidth();
+      var mainCanvasPadding = $mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge());
+      if (width !== mainCanvasPadding) {
+        $mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge(), width + 'px');
+        $container.attr('data-offset-' + Drupal.offCanvas.getEdge(), width);
+        displace();
+      }
+    },
+    getContainer: function getContainer($element) {
+      return $element.dialog('widget');
+    },
+    getEdge: function getEdge() {
+      return document.documentElement.dir === 'rtl' ? 'left' : 'right';
+    }
+  };
+
+  Drupal.behaviors.offCanvasEvents = {
+    attach: function attach() {
+      $(window).once('off-canvas').on({
+        'dialog:beforecreate': function dialogBeforecreate(event, dialog, $element, settings) {
+          if (Drupal.offCanvas.isOffCanvas($element)) {
+            Drupal.offCanvas.beforeCreate({ dialog: dialog, $element: $element, settings: settings });
+          }
+        },
+        'dialog:aftercreate': function dialogAftercreate(event, dialog, $element, settings) {
+          if (Drupal.offCanvas.isOffCanvas($element)) {
+            Drupal.offCanvas.render({ dialog: dialog, $element: $element, settings: settings });
+            Drupal.offCanvas.afterCreate({ $element: $element, settings: settings });
+          }
+        },
+        'dialog:beforeclose': function dialogBeforeclose(event, dialog, $element) {
+          if (Drupal.offCanvas.isOffCanvas($element)) {
+            Drupal.offCanvas.beforeClose({ dialog: dialog, $element: $element });
+          }
+        }
+      });
+    }
+  };
+})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
\ No newline at end of file
diff --git a/core/modules/outside_in/css/off-canvas.motion.css b/core/misc/dialog/off-canvas.motion.css
similarity index 54%
copy from core/modules/outside_in/css/off-canvas.motion.css
copy to core/misc/dialog/off-canvas.motion.css
index ae261870bc..87fbf3016a 100644
--- a/core/modules/outside_in/css/off-canvas.motion.css
+++ b/core/misc/dialog/off-canvas.motion.css
@@ -4,10 +4,6 @@
  *
  * Motion effects are in a separate file so that they can be easily turned off
  * to improve performance if desired.
- *
- * @todo Move motion effects file into a core Off-Canvas library and add a
- *   configuration option for browser rendering performance to disable this
- *   file: https://www.drupal.org/node/2784443.
  */
 
 .dialog-off-canvas__main-canvas {
diff --git a/core/modules/outside_in/css/off-canvas.reset.css b/core/misc/dialog/off-canvas.reset.css
similarity index 100%
copy from core/modules/outside_in/css/off-canvas.reset.css
copy to core/misc/dialog/off-canvas.reset.css
diff --git a/core/modules/outside_in/css/off-canvas.table.css b/core/misc/dialog/off-canvas.table.css
similarity index 96%
copy from core/modules/outside_in/css/off-canvas.table.css
copy to core/misc/dialog/off-canvas.table.css
index 24d2b4c026..03efbd6326 100644
--- a/core/modules/outside_in/css/off-canvas.table.css
+++ b/core/misc/dialog/off-canvas.table.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Visual styling for tables in the Settings Tray module's off canvas tray.
+ * Visual styling for tables in the off-canvas dialog.
  */
 
 #drupal-off-canvas table * {
diff --git a/core/modules/outside_in/css/off-canvas.tabledrag.css b/core/misc/dialog/off-canvas.tabledrag.css
similarity index 94%
copy from core/modules/outside_in/css/off-canvas.tabledrag.css
copy to core/misc/dialog/off-canvas.tabledrag.css
index 20f97954da..edeef831bc 100644
--- a/core/modules/outside_in/css/off-canvas.tabledrag.css
+++ b/core/misc/dialog/off-canvas.tabledrag.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Table drag behavior for Settings Tray module.
+ * Table drag behavior for off-canvas dialog.
  *
  * @see tabledrag.js
  */
@@ -39,7 +39,7 @@
 #drupal-off-canvas a.tabledrag-handle .handle {
   /* Use lighter drag icon against dark background. */
   background-color: transparent;
-  background-image: url(../../../misc/icons/bebebe/move.svg);
+  background-image: url(../icons/bebebe/move.svg);
   background-repeat: no-repeat;
   background-position: center;
   height: auto;
@@ -49,7 +49,7 @@
 }
 #drupal-off-canvas .draggable a.tabledrag-handle:hover .handle,
 #drupal-off-canvas .draggable a.tabledrag-handle:focus .handle {
-  background-image: url(../../../misc/icons/787878/move.svg);
+  background-image: url(../icons/787878/move.svg);
   text-decoration: none;
 }
 #drupal-off-canvas tr td {
diff --git a/core/modules/outside_in/css/off-canvas.theme.css b/core/misc/dialog/off-canvas.theme.css
similarity index 90%
copy from core/modules/outside_in/css/off-canvas.theme.css
copy to core/misc/dialog/off-canvas.theme.css
index 0493e3ce44..e1990a7d46 100644
--- a/core/modules/outside_in/css/off-canvas.theme.css
+++ b/core/misc/dialog/off-canvas.theme.css
@@ -15,7 +15,7 @@
   z-index: 501;
 }
 
-/* Style the tray header. */
+/* Style the off-canvas dialog header. */
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar {
   padding: 1em;
   background: #2d2d2d;
@@ -30,7 +30,7 @@
   visibility: hidden;
 }
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close {
-  background-image: url(../../../misc/icons/bebebe/ex.svg);
+  background-image: url(../icons/bebebe/ex.svg);
   background-position: center center;
   background-repeat: no-repeat;
   background-color: transparent;
@@ -40,7 +40,7 @@
   transition: background .5s ease;
 }
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close:hover {
-  background-image: url(../../../misc/icons/ffffff/ex.svg);
+  background-image: url(../icons/ffffff/ex.svg);
 }
 [dir="rtl"] .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close {
   left: 1em;
@@ -64,7 +64,7 @@
   padding-right: 30px;
 }
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-title:before {
-  background: transparent url(../../../misc/icons/ffffff/pencil.svg) no-repeat scroll center center;
+  background: transparent url(../icons/ffffff/pencil.svg) no-repeat scroll center center;
   background-size: 100% auto;
   content: '';
   display: block;
diff --git a/core/modules/outside_in/css/outside_in.motion.css b/core/modules/outside_in/css/outside_in.motion.css
index d327369137..4cf88b68d9 100644
--- a/core/modules/outside_in/css/outside_in.motion.css
+++ b/core/modules/outside_in/css/outside_in.motion.css
@@ -14,6 +14,6 @@
 /* Transition the editables on the page, their contextual links and their hover states. */
 .dialog-off-canvas__main-canvas .contextual,
 .dialog-off-canvas__main-canvas .js-outside-in-edit-mode .outside-in-editable,
-.dialog-off-canvas__main-canvas.js-tray-open .js-outside-in-edit-mode .outside-in-editable {
+.dialog-off-canvas__main-canvas.js-off-canvas-dialog-open .js-outside-in-edit-mode .outside-in-editable {
   transition: all .7s ease;
 }
diff --git a/core/modules/outside_in/js/off-canvas.es6.js b/core/modules/outside_in/js/off-canvas.es6.js
deleted file mode 100644
index 480561a7c6..0000000000
--- a/core/modules/outside_in/js/off-canvas.es6.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * @file
- * Drupal's off-canvas library.
- *
- * @todo This functionality should extracted into a new core library or a part
- *  of the current drupal.dialog.ajax library.
- *  https://www.drupal.org/node/2784443
- *
- * @private
- */
-
-(function ($, Drupal, debounce, displace) {
-  // The minimum width to use body displace needs to match the width at which
-  // the tray will be %100 width. @see outside_in.module.css
-  const minDisplaceWidth = 768;
-
-  /**
-   * The edge of the screen that the dialog should appear on.
-   *
-   * @type {string}
-   */
-  const edge = document.documentElement.dir === 'rtl' ? 'left' : 'right';
-
-  const $mainCanvasWrapper = $('[data-off-canvas-main-canvas]');
-
-  /**
-   * Resets the size of the dialog.
-   *
-   * @param {jQuery.Event} event
-   *   The event triggered.
-   */
-  function resetSize(event) {
-    const offsets = displace.offsets;
-    const $element = event.data.$element;
-    const $widget = $element.dialog('widget');
-    const $elementScroll = $element.scrollTop();
-
-    const adjustedOptions = {
-      // @see http://api.jqueryui.com/position/
-      position: {
-        my: `${edge} top`,
-        at: `${edge} top${offsets.top !== 0 ? `+${offsets.top}` : ''}`,
-        of: window,
-      },
-    };
-
-    $widget.css({
-      position: 'fixed',
-      height: `${$(window).height() - (offsets.top + offsets.bottom)}px`,
-    });
-
-    $element
-      .dialog('option', adjustedOptions)
-      .trigger('dialogContentResize.off-canvas');
-
-    // Reset the elements scroll position after being repositioned.
-    $element.scrollTop($elementScroll);
-  }
-
-  /**
-   * Adjusts the dialog on resize.
-   *
-   * @param {jQuery.Event} event
-   *   The event triggered.
-   */
-  function handleDialogResize(event) {
-    const $element = event.data.$element;
-    const $widget = $element.dialog('widget');
-
-    const $offsets = $widget.find('> :not(#drupal-off-canvas, .ui-resizable-handle)');
-    let offset = 0;
-    let modalHeight;
-
-    // Let scroll element take all the height available.
-    $element.css({ height: 'auto' });
-    modalHeight = $widget.height();
-    $offsets.each(function () {
-      offset += $(this).outerHeight();
-    });
-
-    // Take internal padding into account.
-    const scrollOffset = $element.outerHeight() - $element.height();
-    $element.height(modalHeight - offset - scrollOffset);
-  }
-
-  /**
-   * Adjusts the body padding when the dialog is resized.
-   *
-   * @param {jQuery.Event} event
-   *   The event triggered.
-   */
-  function bodyPadding(event) {
-    if ($('body').outerWidth() < minDisplaceWidth) {
-      return;
-    }
-    const $element = event.data.$element;
-    const $widget = $element.dialog('widget');
-
-    const width = $widget.outerWidth();
-    const mainCanvasPadding = $mainCanvasWrapper.css(`padding-${edge}`);
-    if (width !== mainCanvasPadding) {
-      $mainCanvasWrapper.css(`padding-${edge}`, `${width}px`);
-      $widget.attr(`data-offset-${edge}`, width);
-      displace();
-    }
-  }
-
-  /**
-   * Attaches off-canvas dialog behaviors.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches event listeners for off-canvas dialogs.
-   */
-  Drupal.behaviors.offCanvasEvents = {
-    attach() {
-      $(window).once('off-canvas').on({
-        'dialog:aftercreate': function (event, dialog, $element, settings) {
-          if ($element.is('#drupal-off-canvas')) {
-            const eventData = { settings, $element };
-            $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title);
-
-            $element
-              .on('dialogresize.off-canvas', eventData, debounce(bodyPadding, 100))
-              .on('dialogContentResize.off-canvas', eventData, handleDialogResize)
-              .on('dialogContentResize.off-canvas', eventData, debounce(bodyPadding, 100))
-              .trigger('dialogresize.off-canvas');
-
-            $element.dialog('widget').attr(`data-offset-${edge}`, '');
-
-            $(window)
-              .on('resize.off-canvas scroll.off-canvas', eventData, debounce(resetSize, 100))
-              .trigger('resize.off-canvas');
-          }
-        },
-        'dialog:beforecreate': function (event, dialog, $element, settings) {
-          if ($element.is('#drupal-off-canvas')) {
-            $('body').addClass('js-tray-open');
-            // @see http://api.jqueryui.com/position/
-            settings.position = {
-              my: 'left top',
-              at: `${edge} top`,
-              of: window,
-            };
-            settings.dialogClass += ' ui-dialog-off-canvas';
-            // Applies initial height to dialog based on window height.
-            // See http://api.jqueryui.com/dialog for all dialog options.
-            settings.height = $(window).height();
-          }
-        },
-        'dialog:beforeclose': function (event, dialog, $element) {
-          if ($element.is('#drupal-off-canvas')) {
-            $('body').removeClass('js-tray-open');
-            // Remove all *.off-canvas events
-            $(document).off('.off-canvas');
-            $(window).off('.off-canvas');
-            $mainCanvasWrapper.css(`padding-${edge}`, 0);
-          }
-        },
-      });
-    },
-  };
-}(jQuery, Drupal, Drupal.debounce, Drupal.displace));
diff --git a/core/modules/outside_in/js/off-canvas.js b/core/modules/outside_in/js/off-canvas.js
deleted file mode 100644
index 85a9e53675..0000000000
--- a/core/modules/outside_in/js/off-canvas.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(function ($, Drupal, debounce, displace) {
-  var minDisplaceWidth = 768;
-
-  var edge = document.documentElement.dir === 'rtl' ? 'left' : 'right';
-
-  var $mainCanvasWrapper = $('[data-off-canvas-main-canvas]');
-
-  function resetSize(event) {
-    var offsets = displace.offsets;
-    var $element = event.data.$element;
-    var $widget = $element.dialog('widget');
-    var $elementScroll = $element.scrollTop();
-
-    var adjustedOptions = {
-      position: {
-        my: edge + ' top',
-        at: edge + ' top' + (offsets.top !== 0 ? '+' + offsets.top : ''),
-        of: window
-      }
-    };
-
-    $widget.css({
-      position: 'fixed',
-      height: $(window).height() - (offsets.top + offsets.bottom) + 'px'
-    });
-
-    $element.dialog('option', adjustedOptions).trigger('dialogContentResize.off-canvas');
-
-    $element.scrollTop($elementScroll);
-  }
-
-  function handleDialogResize(event) {
-    var $element = event.data.$element;
-    var $widget = $element.dialog('widget');
-
-    var $offsets = $widget.find('> :not(#drupal-off-canvas, .ui-resizable-handle)');
-    var offset = 0;
-    var modalHeight = void 0;
-
-    $element.css({ height: 'auto' });
-    modalHeight = $widget.height();
-    $offsets.each(function () {
-      offset += $(this).outerHeight();
-    });
-
-    var scrollOffset = $element.outerHeight() - $element.height();
-    $element.height(modalHeight - offset - scrollOffset);
-  }
-
-  function bodyPadding(event) {
-    if ($('body').outerWidth() < minDisplaceWidth) {
-      return;
-    }
-    var $element = event.data.$element;
-    var $widget = $element.dialog('widget');
-
-    var width = $widget.outerWidth();
-    var mainCanvasPadding = $mainCanvasWrapper.css('padding-' + edge);
-    if (width !== mainCanvasPadding) {
-      $mainCanvasWrapper.css('padding-' + edge, width + 'px');
-      $widget.attr('data-offset-' + edge, width);
-      displace();
-    }
-  }
-
-  Drupal.behaviors.offCanvasEvents = {
-    attach: function attach() {
-      $(window).once('off-canvas').on({
-        'dialog:aftercreate': function dialogAftercreate(event, dialog, $element, settings) {
-          if ($element.is('#drupal-off-canvas')) {
-            var eventData = { settings: settings, $element: $element };
-            $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title);
-
-            $element.on('dialogresize.off-canvas', eventData, debounce(bodyPadding, 100)).on('dialogContentResize.off-canvas', eventData, handleDialogResize).on('dialogContentResize.off-canvas', eventData, debounce(bodyPadding, 100)).trigger('dialogresize.off-canvas');
-
-            $element.dialog('widget').attr('data-offset-' + edge, '');
-
-            $(window).on('resize.off-canvas scroll.off-canvas', eventData, debounce(resetSize, 100)).trigger('resize.off-canvas');
-          }
-        },
-        'dialog:beforecreate': function dialogBeforecreate(event, dialog, $element, settings) {
-          if ($element.is('#drupal-off-canvas')) {
-            $('body').addClass('js-tray-open');
-
-            settings.position = {
-              my: 'left top',
-              at: edge + ' top',
-              of: window
-            };
-            settings.dialogClass += ' ui-dialog-off-canvas';
-
-            settings.height = $(window).height();
-          }
-        },
-        'dialog:beforeclose': function dialogBeforeclose(event, dialog, $element) {
-          if ($element.is('#drupal-off-canvas')) {
-            $('body').removeClass('js-tray-open');
-
-            $(document).off('.off-canvas');
-            $(window).off('.off-canvas');
-            $mainCanvasWrapper.css('padding-' + edge, 0);
-          }
-        }
-      });
-    }
-  };
-})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
\ No newline at end of file
diff --git a/core/modules/outside_in/outside_in.libraries.yml b/core/modules/outside_in/outside_in.libraries.yml
index 06e24a8291..64e1eddd19 100644
--- a/core/modules/outside_in/outside_in.libraries.yml
+++ b/core/modules/outside_in/outside_in.libraries.yml
@@ -17,29 +17,3 @@ drupal.outside_in:
     - core/drupal
     - core/jquery.once
     - core/drupal.ajax
-drupal.off_canvas:
-  version: VERSION
-  js:
-    js/off-canvas.js: {}
-  css:
-    base:
-      css/off-canvas.reset.css: {}
-      css/off-canvas.base.css: {}
-      css/off-canvas.css: {}
-      css/off-canvas.theme.css: { group: 200 }
-    component:
-      css/off-canvas.motion.css: {}
-      css/off-canvas.button.css: {}
-      css/off-canvas.form.css: {}
-      css/off-canvas.table.css: {}
-      css/off-canvas.details.css: {}
-      css/off-canvas.tabledrag.css: {}
-      css/off-canvas.dropbutton.css: {}
-
-  dependencies:
-    - core/jquery
-    - core/drupal
-    - core/drupal.ajax
-    - core/drupal.announce
-    - core/drupal.dialog
-    - core/drupal.dialog.ajax
diff --git a/core/modules/outside_in/outside_in.module b/core/modules/outside_in/outside_in.module
index acded3af11..eb4ada9f5c 100644
--- a/core/modules/outside_in/outside_in.module
+++ b/core/modules/outside_in/outside_in.module
@@ -44,7 +44,7 @@ function outside_in_contextual_links_view_alter(&$element, $items) {
       $element['#links']['outside-inblock-configure']['title'] = t('Quick edit settings');
     }
 
-    $element['#attached']['library'][] = 'outside_in/drupal.off_canvas';
+    $element['#attached']['library'][] = 'core/drupal.dialog.off_canvas';
   }
 }
 
@@ -60,26 +60,6 @@ function outside_in_block_view_alter(array &$build) {
   ];
 }
 
-/**
- * Implements hook_element_info_alter().
- */
-function outside_in_element_info_alter(&$type) {
-  if (isset($type['page'])) {
-    $type['page']['#theme_wrappers']['outside_in_page_wrapper'] = ['#weight' => -1000];
-  }
-}
-
-/**
- * Implements hook_theme().
- */
-function outside_in_theme() {
-  return [
-    'outside_in_page_wrapper' => [
-      'variables' => ['children' => NULL],
-    ],
-  ];
-}
-
 /**
  * Implements hook_entity_type_build().
  */
diff --git a/core/modules/outside_in/outside_in.services.yml b/core/modules/outside_in/outside_in.services.yml
deleted file mode 100644
index ce8214697a..0000000000
--- a/core/modules/outside_in/outside_in.services.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-services:
-  main_content_renderer.off_canvas:
-    class: Drupal\outside_in\Render\MainContent\OffCanvasRenderer
-    arguments: ['@title_resolver', '@renderer']
-    tags:
-      - { name: render.main_content_renderer, format: drupal_dialog.off_canvas }
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
index daf3d1f737..b59b89f3e4 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
@@ -5,6 +5,7 @@
 use Drupal\block\Entity\Block;
 use Drupal\block_content\Entity\BlockContent;
 use Drupal\block_content\Entity\BlockContentType;
+use Drupal\Tests\system\FunctionalJavascript\OffCanvasTestBase;
 use Drupal\user\Entity\Role;
 
 /**
@@ -12,7 +13,7 @@
  *
  * @group outside_in
  */
-class OutsideInBlockFormTest extends OutsideInJavascriptTestBase {
+class OutsideInBlockFormTest extends OffCanvasTestBase {
 
   const TOOLBAR_EDIT_LINK_SELECTOR = '#toolbar-bar div.contextual-toolbar-tab button';
 
@@ -528,4 +529,59 @@ public function testValidationMessages() {
     }
   }
 
+  /**
+   * Clicks a contextual link.
+   *
+   * @todo Remove this function when related trait added in
+   *   https://www.drupal.org/node/2821724.
+   *
+   * @param string $selector
+   *   The selector for the element that contains the contextual link.
+   * @param string $link_locator
+   *   The link id, title, or text.
+   * @param bool $force_visible
+   *   If true then the button will be forced to visible so it can be clicked.
+   */
+  protected function clickContextualLink($selector, $link_locator, $force_visible = TRUE) {
+    if ($force_visible) {
+      $this->toggleContextualTriggerVisibility($selector);
+    }
+
+    $element = $this->getSession()->getPage()->find('css', $selector);
+    $element->find('css', '.contextual button')->press();
+    $element->findLink($link_locator)->click();
+
+    if ($force_visible) {
+      $this->toggleContextualTriggerVisibility($selector);
+    }
+  }
+
+  /**
+   * Toggles the visibility of a contextual trigger.
+   *
+   * @todo Remove this function when related trait added in
+   *   https://www.drupal.org/node/2821724.
+   *
+   * @param string $selector
+   *   The selector for the element that contains the contextual link.
+   */
+  protected function toggleContextualTriggerVisibility($selector) {
+    // Hovering over the element itself with should be enough, but does not
+    // work. Manually remove the visually-hidden class.
+    $this->getSession()->executeScript("jQuery('{$selector} .contextual .trigger').toggleClass('visually-hidden');");
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getTestThemes() {
+    $themes = parent::getTestThemes();
+    // Remove 'seven' theme. Setting Tray "Edit Mode" will not work with 'seven'
+    // because it removes all contextual links the off-canvas dialog should.
+    if (($key = array_search('seven', $themes)) !== FALSE) {
+      unset($themes[$key]);
+    }
+    return $themes;
+  }
+
 }
diff --git a/core/modules/outside_in/src/Tests/Ajax/OffCanvasDialogTest.php b/core/modules/system/src/Tests/Ajax/OffCanvasDialogTest.php
similarity index 85%
rename from core/modules/outside_in/src/Tests/Ajax/OffCanvasDialogTest.php
rename to core/modules/system/src/Tests/Ajax/OffCanvasDialogTest.php
index ce3356f112..6d7ddbb9d4 100644
--- a/core/modules/outside_in/src/Tests/Ajax/OffCanvasDialogTest.php
+++ b/core/modules/system/src/Tests/Ajax/OffCanvasDialogTest.php
@@ -1,30 +1,22 @@
 <?php
 
-namespace Drupal\outside_in\Tests\Ajax;
+namespace Drupal\system\Tests\Ajax;
 
 use Drupal\ajax_test\Controller\AjaxTestController;
 use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
-use Drupal\system\Tests\Ajax\AjaxTestBase;
 
 /**
  * Performs tests on opening and manipulating dialogs via AJAX commands.
  *
- * @group outside_in
+ * @group Ajax
  */
 class OffCanvasDialogTest extends AjaxTestBase {
 
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['outside_in'];
 
   /**
    * Test sending AJAX requests to open and manipulate off-canvas dialog.
    */
   public function testDialog() {
-    $this->drupalLogin($this->drupalCreateUser(['administer contact forms']));
     // Ensure the elements render without notices or exceptions.
     $this->drupalGet('ajax-test/dialog');
 
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index d327d4e74b..cb366ac49c 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -268,6 +268,9 @@ function system_theme() {
       ],
       'template' => 'entity-add-list',
     ],
+    'off_canvas_page_wrapper' => [
+      'variables' => ['children' => NULL],
+    ],
   ]);
 }
 
@@ -1515,3 +1518,12 @@ function system_query_entity_reference_alter(AlterableInterface $query) {
   $handler = $query->getMetadata('entity_reference_selection_handler');
   $handler->entityQueryAlter($query);
 }
+
+/**
+ * Implements hook_element_info_alter().
+ */
+function system_element_info_alter(&$type) {
+  if (isset($type['page'])) {
+    $type['page']['#theme_wrappers']['off_canvas_page_wrapper'] = ['#weight' => -1000];
+  }
+}
diff --git a/core/modules/outside_in/templates/outside-in-page-wrapper.html.twig b/core/modules/system/templates/off-canvas-page-wrapper.html.twig
similarity index 58%
copy from core/modules/outside_in/templates/outside-in-page-wrapper.html.twig
copy to core/modules/system/templates/off-canvas-page-wrapper.html.twig
index 11c7f5311d..98b67ba2c2 100644
--- a/core/modules/outside_in/templates/outside-in-page-wrapper.html.twig
+++ b/core/modules/system/templates/off-canvas-page-wrapper.html.twig
@@ -5,13 +5,13 @@
  *
  * For consistent wrapping to {{ page }} render in all themes. The
  * "data-off-canvas-main-canvas" attribute is required by the off-canvas dialog.
- * This is used by the outside_in/drupal.off_canvas library to select the
- * "main canvas" page element as opposed to the "off canvas" which is the tray
+ * This is used by the core/drupal.dialog.off_canvas library to select the
+ * "main canvas" page element as opposed to the "off canvas" which is the dialog
  * itself. The "main canvas" element must be resized according to the width of
- * the "off canvas" tray so that no portion of the "main canvas" is obstructed
- * by the tray. The tray can vary in width when opened and can be resized by the
- * user. The "data-off-canvas-main-canvas" attribute cannot be removed without
- * breaking the off-canvas dialog functionality.
+ * the "off canvas" dialog so that no portion of the "main canvas" is obstructed
+ * by the off-canvas dialog. The off-canvas dialog can vary in width when opened
+ * and can be resized by the user. The "data-off-canvas-main-canvas" attribute
+ * cannot be removed without breaking the off-canvas dialog functionality.
  *
  * Available variables:
  * - children: Contains the child elements of the page.
@@ -20,7 +20,7 @@
  */
 #}
 {% if children %}
-  <div class="dialog-off-canvas__main-canvas" data-off-canvas-main-canvas >
+  <div class="dialog-off-canvas__main-canvas" data-off-canvas-main-canvas>
     {{ children }}
   </div>
 {% endif %}
diff --git a/core/modules/outside_in/tests/modules/off_canvas_test/off_canvas_test.info.yml b/core/modules/system/tests/modules/off_canvas_test/off_canvas_test.info.yml
similarity index 76%
rename from core/modules/outside_in/tests/modules/off_canvas_test/off_canvas_test.info.yml
rename to core/modules/system/tests/modules/off_canvas_test/off_canvas_test.info.yml
index 8c6cc80242..9680b1842d 100644
--- a/core/modules/outside_in/tests/modules/off_canvas_test/off_canvas_test.info.yml
+++ b/core/modules/system/tests/modules/off_canvas_test/off_canvas_test.info.yml
@@ -4,6 +4,3 @@ description: 'Provides off-canvas test links.'
 package: Testing
 version: VERSION
 core: 8.x
-dependencies:
-  - block
-  - outside_in
diff --git a/core/modules/outside_in/tests/modules/off_canvas_test/off_canvas_test.routing.yml b/core/modules/system/tests/modules/off_canvas_test/off_canvas_test.routing.yml
similarity index 100%
rename from core/modules/outside_in/tests/modules/off_canvas_test/off_canvas_test.routing.yml
rename to core/modules/system/tests/modules/off_canvas_test/off_canvas_test.routing.yml
diff --git a/core/modules/outside_in/tests/modules/off_canvas_test/src/Controller/TestController.php b/core/modules/system/tests/modules/off_canvas_test/src/Controller/TestController.php
similarity index 88%
rename from core/modules/outside_in/tests/modules/off_canvas_test/src/Controller/TestController.php
rename to core/modules/system/tests/modules/off_canvas_test/src/Controller/TestController.php
index 6164b06fc2..ea310fa0bd 100644
--- a/core/modules/outside_in/tests/modules/off_canvas_test/src/Controller/TestController.php
+++ b/core/modules/system/tests/modules/off_canvas_test/src/Controller/TestController.php
@@ -53,11 +53,6 @@ public function linksDisplay() {
           'data-dialog-type' => 'dialog',
           'data-dialog-renderer' => 'off_canvas',
         ],
-        '#attached' => [
-          'library' => [
-            'outside_in/drupal.outside_in',
-          ],
-        ],
       ],
       'off_canvas_link_2' => [
         '#title' => 'Click Me 2!',
@@ -71,11 +66,6 @@ public function linksDisplay() {
             'width' => 555,
           ]),
         ],
-        '#attached' => [
-          'library' => [
-            'outside_in/drupal.outside_in',
-          ],
-        ],
       ],
       'other_dialog_links' => [
         '#title' => 'Display more links!',
@@ -86,10 +76,10 @@ public function linksDisplay() {
           'data-dialog-type' => 'dialog',
           'data-dialog-renderer' => 'off_canvas',
         ],
-        '#attached' => [
-          'library' => [
-            'outside_in/drupal.outside_in',
-          ],
+      ],
+      '#attached' => [
+        'library' => [
+          'core/drupal.dialog.ajax',
         ],
       ],
     ];
@@ -129,11 +119,6 @@ public function otherDialogLinks() {
           ],
         ],
       ],
-      '#attached' => [
-        'library' => [
-          'outside_in/drupal.outside_in',
-        ],
-      ],
     ];
   }
 
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OffCanvasTest.php b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTest.php
similarity index 89%
rename from core/modules/outside_in/tests/src/FunctionalJavascript/OffCanvasTest.php
rename to core/modules/system/tests/src/FunctionalJavascript/OffCanvasTest.php
index 2f64d9fe2c..80b1980eea 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OffCanvasTest.php
+++ b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTest.php
@@ -1,22 +1,18 @@
 <?php
 
-namespace Drupal\Tests\outside_in\FunctionalJavascript;
+namespace Drupal\Tests\system\FunctionalJavascript;
 
 /**
  * Tests the off-canvas dialog functionality.
  *
  * @group outside_in
  */
-class OffCanvasTest extends OutsideInJavascriptTestBase {
+class OffCanvasTest extends OffCanvasTestBase {
 
   /**
    * {@inheritdoc}
    */
   public static $modules = [
-    'block',
-    'system',
-    'toolbar',
-    'outside_in',
     'off_canvas_test',
   ];
 
@@ -48,7 +44,7 @@ public function testOffCanvasLinks() {
         $web_assert->elementExists('css', '#drupal-off-canvas');
         // Check that response text is on page.
         $web_assert->pageTextContains("Thing $link_index says hello");
-        $off_canvas_tray = $this->getTray();
+        $off_canvas_tray = $this->getOffCanvasDialog();
 
         // Check that tray is visible.
         $this->assertEquals(TRUE, $off_canvas_tray->isVisible());
@@ -111,13 +107,4 @@ public function testNarrowWidth() {
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function getTestThemes() {
-    // Add 'seven' theme. Setting Tray "Edit Mode" will not work with 'seven'
-    // because it removes all contextual links the off-canvas dialog should.
-    return array_merge(parent::getTestThemes(), ['seven']);
-  }
-
 }
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTestBase.php
similarity index 54%
rename from core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
rename to core/modules/system/tests/src/FunctionalJavascript/OffCanvasTestBase.php
index 2ce2bf64d6..6b74b5efcb 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
+++ b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTestBase.php
@@ -1,13 +1,13 @@
 <?php
 
-namespace Drupal\Tests\outside_in\FunctionalJavascript;
+namespace Drupal\Tests\system\FunctionalJavascript;
 
 use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
 
 /**
- * Base class contains common test functionality for the Settings Tray module.
+ * Base class contains common test functionality for the Off-canvas dialog.
  */
-abstract class OutsideInJavascriptTestBase extends JavascriptTestBase {
+abstract class OffCanvasTestBase extends JavascriptTestBase {
 
   /**
    * {@inheritdoc}
@@ -15,8 +15,8 @@
   protected function drupalGet($path, array $options = [], array $headers = []) {
     $return = parent::drupalGet($path, $options, $headers);
 
-    // After the page loaded we need to additionally wait until the settings
-    // tray Ajax activity is done.
+    // After the page loaded we need to additionally wait until the off-canvas
+    // dialog Ajax activity is done.
     $this->assertSession()->assertWaitOnAjaxRequest();
 
     return $return;
@@ -41,6 +41,9 @@ protected function enableTheme($theme) {
    */
   protected function waitForOffCanvasToOpen() {
     $web_assert = $this->assertSession();
+    // Wait just slightly longer than the off-canvas dialog CSS animation.
+    // @see core/misc/dialog/off-canvas.motion.css
+    $this->getSession()->wait(800);
     $web_assert->assertWaitOnAjaxRequest();
     $this->assertElementVisibleAfterWait('css', '#drupal-off-canvas');
   }
@@ -57,10 +60,10 @@ protected function waitForOffCanvasToClose() {
    *
    * @return \Behat\Mink\Element\NodeElement|null
    */
-  protected function getTray() {
-    $tray = $this->getSession()->getPage()->find('css', '.ui-dialog[aria-describedby="drupal-off-canvas"]');
-    $this->assertEquals(FALSE, empty($tray), 'The tray was found.');
-    return $tray;
+  protected function getOffCanvasDialog() {
+    $off_canvas_dialog = $this->getSession()->getPage()->find('css', '.ui-dialog[aria-describedby="drupal-off-canvas"]');
+    $this->assertEquals(FALSE, empty($off_canvas_dialog), 'The off-canvas dialog was found.');
+    return $off_canvas_dialog;
   }
 
   /**
@@ -70,54 +73,14 @@ protected function getTray() {
    *   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 = "(jQuery('$selector').length == 0)";
     $this->assertJsCondition($condition, $timeout);
   }
 
-  /**
-   * Clicks a contextual link.
-   *
-   * @todo Remove this function when related trait added in
-   *   https://www.drupal.org/node/2821724.
-   *
-   * @param string $selector
-   *   The selector for the element that contains the contextual link.
-   * @param string $link_locator
-   *   The link id, title, or text.
-   * @param bool $force_visible
-   *   If true then the button will be forced to visible so it can be clicked.
-   */
-  protected function clickContextualLink($selector, $link_locator, $force_visible = TRUE) {
-    if ($force_visible) {
-      $this->toggleContextualTriggerVisibility($selector);
-    }
-
-    $element = $this->getSession()->getPage()->find('css', $selector);
-    $element->find('css', '.contextual button')->press();
-    $element->findLink($link_locator)->click();
-
-    if ($force_visible) {
-      $this->toggleContextualTriggerVisibility($selector);
-    }
-  }
-
-  /**
-   * Toggles the visibility of a contextual trigger.
-   *
-   * @todo Remove this function when related trait added in
-   *   https://www.drupal.org/node/2821724.
-   *
-   * @param string $selector
-   *   The selector for the element that contains the contextual link.
-   */
-  protected function toggleContextualTriggerVisibility($selector) {
-    // Hovering over the element itself with should be enough, but does not
-    // work. Manually remove the visually-hidden class.
-    $this->getSession()->executeScript("jQuery('{$selector} .contextual .trigger').toggleClass('visually-hidden');");
-  }
-
   /**
    * Get themes to test.
    *
@@ -125,7 +88,7 @@ protected function toggleContextualTriggerVisibility($selector) {
    *   Theme names to test.
    */
   protected function getTestThemes() {
-    return ['bartik', 'stark', 'classy', 'stable'];
+    return ['bartik', 'stark', 'classy', 'stable', 'seven'];
   }
 
   /**
diff --git a/core/modules/outside_in/tests/src/Unit/Ajax/OpenOffCanvasDialogCommandTest.php b/core/tests/Drupal/Tests/Core/Ajax/OpenOffCanvasDialogCommandTest.php
similarity index 81%
rename from core/modules/outside_in/tests/src/Unit/Ajax/OpenOffCanvasDialogCommandTest.php
rename to core/tests/Drupal/Tests/Core/Ajax/OpenOffCanvasDialogCommandTest.php
index 314fd1c2f3..e2d933a657 100644
--- a/core/modules/outside_in/tests/src/Unit/Ajax/OpenOffCanvasDialogCommandTest.php
+++ b/core/tests/Drupal/Tests/Core/Ajax/OpenOffCanvasDialogCommandTest.php
@@ -1,13 +1,13 @@
 <?php
 
-namespace Drupal\Tests\outside_in\Unit\Ajax;
+namespace Drupal\Tests\Core\Ajax;
 
-use Drupal\outside_in\Ajax\OpenOffCanvasDialogCommand;
+use Drupal\Core\Ajax\OpenOffCanvasDialogCommand;
 use Drupal\Tests\UnitTestCase;
 
 /**
- * @coversDefaultClass \Drupal\outside_in\Ajax\OpenOffCanvasDialogCommand
- * @group outside_in
+ * @coversDefaultClass \Drupal\Core\Ajax\OpenOffCanvasDialogCommand
+ * @group Ajax
  */
 class OpenOffCanvasDialogCommandTest extends UnitTestCase {
 
diff --git a/core/modules/outside_in/css/off-canvas.base.css b/core/themes/stable/css/core/dialog/off-canvas.base.css
similarity index 94%
rename from core/modules/outside_in/css/off-canvas.base.css
rename to core/themes/stable/css/core/dialog/off-canvas.base.css
index aaa713dbbe..3c49646003 100644
--- a/core/modules/outside_in/css/off-canvas.base.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.base.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Set base styles for the settings tray.
+ * Set base styles for the off-canvas dialog.
  */
 
 /* Set some global attributes. */
@@ -217,18 +217,18 @@
 }
 #drupal-off-canvas .messages--status {
   background-color: #f3faef;
-  background-image: url(../../../misc/icons/73b355/check.svg);
+  background-image: url(../../../images/core/icons/73b355/check.svg);
   color: #325e1c;
 }
 #drupal-off-canvas .messages--warning {
   background-color: #fdf8ed;
-  background-image: url(../../../misc/icons/e29700/warning.svg);
+  background-image: url(../../../images/core/icons/e29700/warning.svg);
   color: #734c00;
 }
 
 #drupal-off-canvas .messages--error {
   background-color: #fcf4f2;
-  background-image: url(../../../misc/icons/e32700/error.svg);
+  background-image: url(../../../images/core/icons/e32700/error.svg);
   color: #a51b00;
 }
 
diff --git a/core/modules/outside_in/css/off-canvas.button.css b/core/themes/stable/css/core/dialog/off-canvas.button.css
similarity index 96%
rename from core/modules/outside_in/css/off-canvas.button.css
rename to core/themes/stable/css/core/dialog/off-canvas.button.css
index 2b734f8a81..1f8ed5537d 100644
--- a/core/modules/outside_in/css/off-canvas.button.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.button.css
@@ -1,8 +1,8 @@
 /**
  * @file
- * Visual styling for buttons in the off canvas tray.
+ * Visual styling for buttons in the off-canvas dialog.
  *
- * See seven/css/components/buttons.css
+ * @see seven/css/components/buttons.css
  */
 
 #drupal-off-canvas button,
diff --git a/core/modules/outside_in/css/off-canvas.css b/core/themes/stable/css/core/dialog/off-canvas.css
similarity index 69%
rename from core/modules/outside_in/css/off-canvas.css
rename to core/themes/stable/css/core/dialog/off-canvas.css
index d7f3258b26..52a8b9e079 100644
--- a/core/modules/outside_in/css/off-canvas.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.css
@@ -1,8 +1,6 @@
 /**
  * @file
  * CSS for off-canvas dialog.
- *
- * @todo Move CSS into core dialog library https://www.drupal.org/node/2784443.
  */
 
 /* Position the off-canvas dialog container outside the right of the viewport. */
@@ -23,14 +21,14 @@
   text-align: right;
 }
 
-/* Position the dialog-off-canvas tray container outside the right of the viewport. */
+/* Position the off-canvas dialog container outside the right of the viewport. */
 .ui-dialog-off-canvas {
   box-sizing: border-box;
   height: 100%;
   overflow: visible;
 }
 
-/* Wrap the form that's inside the dialog-off-canvas tray. */
+/* Wrap the form that's inside the off-canvas dialog. */
 .ui-dialog-off-canvas #drupal-off-canvas {
   padding: 0 20px;
   /* Prevent horizontal scrollbar. */
@@ -42,15 +40,15 @@
 }
 
 /*
- * Force the tray to be 100% width at the same breakpoint the dialog system uses
- * to expand dialog widths.
+ * Force the off-canvas dialog to be 100% width at the same breakpoint the
+ * dialog system uses to expand dialog widths.
  */
 @media all and (max-width: 48em) { /* 768px */
   .ui-dialog.ui-dialog-off-canvas {
     width: 100% !important;
   }
-  /* When tray is at 100% width stop the body from scrolling */
-  .js-tray-open {
+  /* When off-canvas dialog is at 100% width stop the body from scrolling */
+  .js-off-canvas-dialog-open {
     height: 100%;
     overflow-y: hidden;
   }
diff --git a/core/modules/outside_in/css/off-canvas.details.css b/core/themes/stable/css/core/dialog/off-canvas.details.css
similarity index 93%
rename from core/modules/outside_in/css/off-canvas.details.css
rename to core/themes/stable/css/core/dialog/off-canvas.details.css
index dcac6a5b04..fcd526f0b0 100644
--- a/core/modules/outside_in/css/off-canvas.details.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.details.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Visual styling for summary and details in the Settings Tray module's off canvas tray.
+ * Visual styling for summary and details in the off-canvas dialog.
  */
 
 #drupal-off-canvas details,
diff --git a/core/modules/outside_in/css/off-canvas.dropbutton.css b/core/themes/stable/css/core/dialog/off-canvas.dropbutton.css
similarity index 97%
rename from core/modules/outside_in/css/off-canvas.dropbutton.css
rename to core/themes/stable/css/core/dialog/off-canvas.dropbutton.css
index e467a4f341..99f5c61a9d 100644
--- a/core/modules/outside_in/css/off-canvas.dropbutton.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.dropbutton.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Styles for dropbuttons in the off-canvas tray.
+ * Styles for dropbuttons in the off-canvas dialog.
  */
 
 #drupal-off-canvas .dropbutton-wrapper,
@@ -241,7 +241,7 @@
   content: '.';
   display: block;
   color: transparent;
-  background: transparent url(../../../misc/icons/ffffff/pencil.svg) no-repeat center;
+  background: transparent url(../../../images/core/icons/ffffff/pencil.svg) no-repeat center;
   background-size: 14px;
 }
 
diff --git a/core/modules/outside_in/css/off-canvas.form.css b/core/themes/stable/css/core/dialog/off-canvas.form.css
similarity index 97%
rename from core/modules/outside_in/css/off-canvas.form.css
rename to core/themes/stable/css/core/dialog/off-canvas.form.css
index 254b2c74e9..217f3d1f2c 100644
--- a/core/modules/outside_in/css/off-canvas.form.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.form.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Visual styling for forms in the Settings Tray module's off canvas tray.
+ * Visual styling for forms in the off-canvas dialog.
  */
 
 #drupal-off-canvas form {
@@ -74,6 +74,7 @@
   font-size: 14px;
   color: #333;
   line-height: 16px;
+  cursor: pointer;
 }
 /* Reduce contrast for fields against dark background. */
 #drupal-off-canvas .form-text,
@@ -131,6 +132,5 @@
 }
 #drupal-off-canvas .ui-autocomplete li a {
   color: #595959 !important;
-  cursor: pointer;
   padding: 5px;
 }
diff --git a/core/modules/outside_in/css/off-canvas.motion.css b/core/themes/stable/css/core/dialog/off-canvas.motion.css
similarity index 54%
rename from core/modules/outside_in/css/off-canvas.motion.css
rename to core/themes/stable/css/core/dialog/off-canvas.motion.css
index ae261870bc..87fbf3016a 100644
--- a/core/modules/outside_in/css/off-canvas.motion.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.motion.css
@@ -4,10 +4,6 @@
  *
  * Motion effects are in a separate file so that they can be easily turned off
  * to improve performance if desired.
- *
- * @todo Move motion effects file into a core Off-Canvas library and add a
- *   configuration option for browser rendering performance to disable this
- *   file: https://www.drupal.org/node/2784443.
  */
 
 .dialog-off-canvas__main-canvas {
diff --git a/core/modules/outside_in/css/off-canvas.reset.css b/core/themes/stable/css/core/dialog/off-canvas.reset.css
similarity index 100%
rename from core/modules/outside_in/css/off-canvas.reset.css
rename to core/themes/stable/css/core/dialog/off-canvas.reset.css
diff --git a/core/modules/outside_in/css/off-canvas.table.css b/core/themes/stable/css/core/dialog/off-canvas.table.css
similarity index 96%
rename from core/modules/outside_in/css/off-canvas.table.css
rename to core/themes/stable/css/core/dialog/off-canvas.table.css
index 24d2b4c026..03efbd6326 100644
--- a/core/modules/outside_in/css/off-canvas.table.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.table.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Visual styling for tables in the Settings Tray module's off canvas tray.
+ * Visual styling for tables in the off-canvas dialog.
  */
 
 #drupal-off-canvas table * {
diff --git a/core/modules/outside_in/css/off-canvas.tabledrag.css b/core/themes/stable/css/core/dialog/off-canvas.tabledrag.css
similarity index 93%
rename from core/modules/outside_in/css/off-canvas.tabledrag.css
rename to core/themes/stable/css/core/dialog/off-canvas.tabledrag.css
index 20f97954da..33f670aad5 100644
--- a/core/modules/outside_in/css/off-canvas.tabledrag.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.tabledrag.css
@@ -1,6 +1,6 @@
 /**
  * @file
- * Table drag behavior for Settings Tray module.
+ * Table drag behavior for off-canvas dialog.
  *
  * @see tabledrag.js
  */
@@ -38,8 +38,8 @@
 }
 #drupal-off-canvas a.tabledrag-handle .handle {
   /* Use lighter drag icon against dark background. */
+  background-image: url(../../../images/core/icons/bebebe/move.svg);
   background-color: transparent;
-  background-image: url(../../../misc/icons/bebebe/move.svg);
   background-repeat: no-repeat;
   background-position: center;
   height: auto;
@@ -49,7 +49,7 @@
 }
 #drupal-off-canvas .draggable a.tabledrag-handle:hover .handle,
 #drupal-off-canvas .draggable a.tabledrag-handle:focus .handle {
-  background-image: url(../../../misc/icons/787878/move.svg);
+  background-image: url(../../../images/core/icons/787878/move.svg);
   text-decoration: none;
 }
 #drupal-off-canvas tr td {
diff --git a/core/modules/outside_in/css/off-canvas.theme.css b/core/themes/stable/css/core/dialog/off-canvas.theme.css
similarity index 89%
rename from core/modules/outside_in/css/off-canvas.theme.css
rename to core/themes/stable/css/core/dialog/off-canvas.theme.css
index 0493e3ce44..89eb682db4 100644
--- a/core/modules/outside_in/css/off-canvas.theme.css
+++ b/core/themes/stable/css/core/dialog/off-canvas.theme.css
@@ -15,7 +15,7 @@
   z-index: 501;
 }
 
-/* Style the tray header. */
+/* Style the off-canvas dialog header. */
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar {
   padding: 1em;
   background: #2d2d2d;
@@ -30,7 +30,7 @@
   visibility: hidden;
 }
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close {
-  background-image: url(../../../misc/icons/bebebe/ex.svg);
+  background-image: url(../../../images/core/icons/bebebe/ex.svg);
   background-position: center center;
   background-repeat: no-repeat;
   background-color: transparent;
@@ -40,7 +40,7 @@
   transition: background .5s ease;
 }
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close:hover {
-  background-image: url(../../../misc/icons/ffffff/ex.svg);
+  background-image: url(../../../images/core/icons/ffffff/ex.svg);
 }
 [dir="rtl"] .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close {
   left: 1em;
@@ -64,7 +64,7 @@
   padding-right: 30px;
 }
 .ui-dialog.ui-dialog-off-canvas .ui-dialog-title:before {
-  background: transparent url(../../../misc/icons/ffffff/pencil.svg) no-repeat scroll center center;
+  background: transparent url(../../../images/core/icons/ffffff/pencil.svg) no-repeat scroll center center;
   background-size: 100% auto;
   content: '';
   display: block;
diff --git a/core/themes/stable/stable.info.yml b/core/themes/stable/stable.info.yml
index 251ecbd534..1e437f9d4c 100644
--- a/core/themes/stable/stable.info.yml
+++ b/core/themes/stable/stable.info.yml
@@ -57,6 +57,22 @@ libraries-override:
       component:
         css/contextual.toolbar.css: css/contextual/contextual.toolbar.css
 
+  core/drupal.dialog.off_canvas:
+    css:
+      base:
+        misc/dialog/off-canvas.reset.css: css/core/dialog/off-canvas.reset.css
+        misc/dialog/off-canvas.base.css: css/core/dialog/off-canvas.base.css
+        misc/dialog/off-canvas.css: css/core/dialog/off-canvas.css
+        misc/dialog/off-canvas.theme.css: css/core/dialog/off-canvas.theme.css
+      component:
+        misc/dialog/off-canvas.motion.css: css/core/dialog/off-canvas.motion.css
+        misc/dialog/off-canvas.button.css: css/core/dialog/off-canvas.button.css
+        misc/dialog/off-canvas.form.css: css/core/dialog/off-canvas.form.css
+        misc/dialog/off-canvas.table.css: css/core/dialog/off-canvas.table.css
+        misc/dialog/off-canvas.details.css: css/core/dialog/off-canvas.details.css
+        misc/dialog/off-canvas.tabledrag.css: css/core/dialog/off-canvas.tabledrag.css
+        misc/dialog/off-canvas.dropbutton.css: css/core/dialog/off-canvas.dropbutton.css
+
   core/drupal.dropbutton:
     css:
       component:
diff --git a/core/modules/outside_in/templates/outside-in-page-wrapper.html.twig b/core/themes/stable/templates/content/off-canvas-page-wrapper.html.twig
similarity index 52%
rename from core/modules/outside_in/templates/outside-in-page-wrapper.html.twig
rename to core/themes/stable/templates/content/off-canvas-page-wrapper.html.twig
index 11c7f5311d..11993371c4 100644
--- a/core/modules/outside_in/templates/outside-in-page-wrapper.html.twig
+++ b/core/themes/stable/templates/content/off-canvas-page-wrapper.html.twig
@@ -1,26 +1,24 @@
 {#
 /**
  * @file
- * Default theme implementation for a page wrapper.
+ * Theme override for page wrapper.
  *
  * For consistent wrapping to {{ page }} render in all themes. The
  * "data-off-canvas-main-canvas" attribute is required by the off-canvas dialog.
- * This is used by the outside_in/drupal.off_canvas library to select the
- * "main canvas" page element as opposed to the "off canvas" which is the tray
+ * This is used by the core/drupal.dialog.off_canvas library to select the
+ * "main canvas" page element as opposed to the "off canvas" which is the dialog
  * itself. The "main canvas" element must be resized according to the width of
- * the "off canvas" tray so that no portion of the "main canvas" is obstructed
- * by the tray. The tray can vary in width when opened and can be resized by the
- * user. The "data-off-canvas-main-canvas" attribute cannot be removed without
- * breaking the off-canvas dialog functionality.
+ * the "off canvas" dialog so that no portion of the "main canvas" is obstructed
+ * by the off-canvas dialog. The off-canvas dialog can vary in width when opened
+ * and can be resized by the user. The "data-off-canvas-main-canvas" attribute
+ * cannot be removed without breaking the off-canvas dialog functionality.
  *
  * Available variables:
  * - children: Contains the child elements of the page.
- *
- * @ingroup themeable
  */
 #}
 {% if children %}
-  <div class="dialog-off-canvas__main-canvas" data-off-canvas-main-canvas >
+  <div class="dialog-off-canvas__main-canvas" data-off-canvas-main-canvas>
     {{ children }}
   </div>
 {% endif %}
