DevTools: Convert to Shadow DOM and Custom Elements v1

Bug: 685385
Change-Id: I027e84d8003b7799492211d5fcf8348cd91fd799
Reviewed-on: https://chromium-review.googlesource.com/c/1422962
Reviewed-by: Dmitry Gozman <[email protected]>
Commit-Queue: Joel Einbinder <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#625513}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: b00e6ea1c9b4db5d743c7c204b1f63abf89e0398
diff --git a/front_end/accessibility/AXBreadcrumbsPane.js b/front_end/accessibility/AXBreadcrumbsPane.js
index 34708e0..9075c5e 100644
--- a/front_end/accessibility/AXBreadcrumbsPane.js
+++ b/front_end/accessibility/AXBreadcrumbsPane.js
@@ -112,7 +112,7 @@
   _onKeyDown(event) {
     if (!this._preselectedBreadcrumb)
       return;
-    if (!event.path.some(element => element === this._preselectedBreadcrumb.element()))
+    if (!event.composedPath().some(element => element === this._preselectedBreadcrumb.element()))
       return;
     if (event.shiftKey || event.metaKey || event.ctrlKey)
       return;
diff --git a/front_end/accessibility/AccessibilityNodeView.js b/front_end/accessibility/AccessibilityNodeView.js
index 0706be5..f7776e3 100644
--- a/front_end/accessibility/AccessibilityNodeView.js
+++ b/front_end/accessibility/AccessibilityNodeView.js
@@ -151,7 +151,7 @@
    * @return {!Element}
    */
   static createExclamationMark(tooltip) {
-    const exclamationElement = createElement('label', 'dt-icon-label');
+    const exclamationElement = createElement('span', 'dt-icon-label');
     exclamationElement.type = 'smallicon-warning';
     exclamationElement.title = tooltip;
     return exclamationElement;
diff --git a/front_end/accessibility/accessibilityNode.css b/front_end/accessibility/accessibilityNode.css
index a6e59ca..7b624a9 100644
--- a/front_end/accessibility/accessibilityNode.css
+++ b/front_end/accessibility/accessibilityNode.css
@@ -47,7 +47,7 @@
     padding-left: 4px;
 }
 
-.tree-outline label[is=dt-icon-label] {
+.tree-outline span[is=dt-icon-label] {
     position: relative;
     left: -11px;
 }
@@ -74,7 +74,7 @@
     left: -2px;
 }
 
-.tree-outline label[is=dt-icon-label] + .ax-name {
+.tree-outline span[is=dt-icon-label] + .ax-name {
     margin-left: -11px;
 }
 
diff --git a/front_end/changes/changesView.css b/front_end/changes/changesView.css
index 8d3ad90..552e9ec 100644
--- a/front_end/changes/changesView.css
+++ b/front_end/changes/changesView.css
@@ -3,14 +3,15 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-.insertion-point-main{
+[slot=insertion-point-main]{
     flex-direction: column;
     display: flex;
 }
 
-.insertion-point-sidebar {
+[slot=insertion-point-sidebar] {
     overflow: auto;
 }
+
 .editor-container{
     flex: 1;
 }
diff --git a/front_end/console/ConsoleViewMessage.js b/front_end/console/ConsoleViewMessage.js
index c1c8050..5279e4e 100644
--- a/front_end/console/ConsoleViewMessage.js
+++ b/front_end/console/ConsoleViewMessage.js
@@ -1328,7 +1328,7 @@
       return;
 
     if (!this._repeatCountElement) {
-      this._repeatCountElement = createElementWithClass('label', 'console-message-repeat-count', 'dt-small-bubble');
+      this._repeatCountElement = createElementWithClass('span', 'console-message-repeat-count', 'dt-small-bubble');
       switch (this._message.level) {
         case SDK.ConsoleMessage.MessageLevel.Warning:
           this._repeatCountElement.type = 'warning';
diff --git a/front_end/console_counters/WarningErrorCounter.js b/front_end/console_counters/WarningErrorCounter.js
index b51e2ef..b17e8ae 100644
--- a/front_end/console_counters/WarningErrorCounter.js
+++ b/front_end/console_counters/WarningErrorCounter.js
@@ -39,7 +39,7 @@
    */
   _createItem(shadowRoot, iconType) {
     const item = createElementWithClass('span', 'counter-item');
-    const icon = item.createChild('label', '', 'dt-icon-label');
+    const icon = item.createChild('span', '', 'dt-icon-label');
     icon.type = iconType;
     const text = icon.createChild('span');
     shadowRoot.appendChild(item);
diff --git a/front_end/console_counters/errorWarningCounter.css b/front_end/console_counters/errorWarningCounter.css
index d6ad447..ee6de7a 100644
--- a/front_end/console_counters/errorWarningCounter.css
+++ b/front_end/console_counters/errorWarningCounter.css
@@ -18,10 +18,6 @@
     margin-left: 6px;
 }
 
-.counter-item label {
-    cursor: inherit;
-}
-
 .counter-item.counter-item-first {
     margin-left: 0;
 }
diff --git a/front_end/dom_extension/DOMExtension.js b/front_end/dom_extension/DOMExtension.js
index 95253a4..708adc2 100644
--- a/front_end/dom_extension/DOMExtension.js
+++ b/front_end/dom_extension/DOMExtension.js
@@ -270,10 +270,12 @@
  */
 Node.prototype.hasSelection = function() {
   // TODO(luoe): use contains(node, {includeShadow: true}) when it is fixed for shadow dom.
-  const contents = this.querySelectorAll('content');
-  for (const content of contents) {
-    if (Array.prototype.some.call(content.getDistributedNodes(), node => node.hasSelection()))
-      return true;
+  if (this instanceof Element) {
+    const slots = this.querySelectorAll('slot');
+    for (const slot of slots) {
+      if (Array.prototype.some.call(slot.assignedNodes(), node => node.hasSelection()))
+        return true;
+    }
   }
 
   const selection = this.getComponentSelection();
@@ -299,10 +301,11 @@
  * @param {string} tagName
  * @param {string=} customElementType
  * @return {!Element}
+ * @suppress {checkTypes}
  * @suppressGlobalPropertiesCheck
  */
 function createElement(tagName, customElementType) {
-  return document.createElement(tagName, customElementType || '');
+  return document.createElement(tagName, {is: customElementType});
 }
 
 /**
@@ -318,10 +321,11 @@
  * @param {string} elementName
  * @param {string=} className
  * @param {string=} customElementType
+ * @suppress {checkTypes}
  * @return {!Element}
  */
 Document.prototype.createElementWithClass = function(elementName, className, customElementType) {
-  const element = this.createElement(elementName, customElementType || '');
+  const element = this.createElement(elementName, {is: customElementType});
   if (className)
     element.className = className;
   return element;
@@ -651,7 +655,7 @@
   if (this.shadowRoot)
     return this.shadowRoot;
 
-  const distributedNodes = this.getDistributedNodes ? this.getDistributedNodes() : [];
+  const distributedNodes = this instanceof HTMLSlotElement ? this.assignedNodes() : [];
 
   if (distributedNodes.length)
     return distributedNodes[0];
@@ -668,7 +672,7 @@
     if (sibling)
       return sibling;
 
-    node = insertionPoint(node) || node.parentNodeOrShadowHost();
+    node = node.assignedSlot || node.parentNodeOrShadowHost();
   }
 
   /**
@@ -676,10 +680,9 @@
    * @return {?Node}
    */
   function nextSibling(node) {
-    const parent = insertionPoint(node);
-    if (!parent)
+    if (!node.assignedSlot)
       return node.nextSibling;
-    const distributedNodes = parent.getDistributedNodes ? parent.getDistributedNodes() : [];
+    const distributedNodes = node.assignedSlot.assignedNodes();
 
     const position = Array.prototype.indexOf.call(distributedNodes, node);
     if (position + 1 < distributedNodes.length)
@@ -687,15 +690,6 @@
     return null;
   }
 
-  /**
-   * @param {!Node} node
-   * @return {?Node}
-   */
-  function insertionPoint(node) {
-    const insertionPoints = node.getDestinationInsertionPoints ? node.getDestinationInsertionPoints() : [];
-    return insertionPoints.length > 0 ? insertionPoints[insertionPoints.length - 1] : null;
-  }
-
   return null;
 };
 
diff --git a/front_end/elements/ElementsSidebarPane.js b/front_end/elements/ElementsSidebarPane.js
index 5676b09..1f76f3d 100644
--- a/front_end/elements/ElementsSidebarPane.js
+++ b/front_end/elements/ElementsSidebarPane.js
@@ -5,8 +5,11 @@
  * @unrestricted
  */
 Elements.ElementsSidebarPane = class extends UI.VBox {
-  constructor() {
-    super(true);
+  /**
+   * @param {boolean=} delegatesFocus
+   */
+  constructor(delegatesFocus) {
+    super(true, delegatesFocus);
     this.element.classList.add('flex-none');
     this._computedStyleModel = new Elements.ComputedStyleModel();
     this._computedStyleModel.addEventListener(
diff --git a/front_end/elements/StylesSidebarPane.js b/front_end/elements/StylesSidebarPane.js
index ee5ff65..9198aa8 100644
--- a/front_end/elements/StylesSidebarPane.js
+++ b/front_end/elements/StylesSidebarPane.js
@@ -29,10 +29,9 @@
 
 Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane {
   constructor() {
-    super();
+    super(true /* delegatesFocus */);
     this.setMinimumSize(96, 26);
     this.registerRequiredCSS('elements/stylesSidebarPane.css');
-    this.element.tabIndex = -1;
 
     Common.moduleSetting('colorFormat').addChangeListener(this.update.bind(this));
     Common.moduleSetting('textEditorIndent').addChangeListener(this.update.bind(this));
@@ -95,7 +94,7 @@
    * @return {!Element}
    */
   static createExclamationMark(property) {
-    const exclamationElement = createElement('label', 'dt-icon-label');
+    const exclamationElement = createElement('span', 'dt-icon-label');
     exclamationElement.className = 'exclamation-mark';
     if (!Elements.StylesSidebarPane.ignoreErrorsForProperty(property))
       exclamationElement.type = 'smallicon-warning';
diff --git a/front_end/elements/classesPaneWidget.css b/front_end/elements/classesPaneWidget.css
index ee810fe..01aec13 100644
--- a/front_end/elements/classesPaneWidget.css
+++ b/front_end/elements/classesPaneWidget.css
@@ -16,7 +16,7 @@
     justify-content: flex-start;
 }
 
-.styles-element-classes-pane label {
+.styles-element-classes-pane [is=dt-checkbox] {
     margin-right: 15px;
 }
 
diff --git a/front_end/emulation/DeviceModeView.js b/front_end/emulation/DeviceModeView.js
index e77cf26..144a61b 100644
--- a/front_end/emulation/DeviceModeView.js
+++ b/front_end/emulation/DeviceModeView.js
@@ -74,7 +74,7 @@
     this._bottomResizerElement.title = Common.UIString('Double-click for full height');
 
     this._pageArea = this._screenArea.createChild('div', 'device-mode-page-area');
-    this._pageArea.createChild('content');
+    this._pageArea.createChild('slot');
   }
 
   _populatePresetsContainer() {
diff --git a/front_end/emulation/sensors.css b/front_end/emulation/sensors.css
index e7177d9..acac8d9 100644
--- a/front_end/emulation/sensors.css
+++ b/front_end/emulation/sensors.css
@@ -9,10 +9,6 @@
     display: block;
 }
 
-.sensors-view label {
-    margin-bottom: 10px;
-}
-
 .sensors-view input {
     width: 100%;
     max-width: 100px;
diff --git a/front_end/inline_editor/CSSShadowEditor.js b/front_end/inline_editor/CSSShadowEditor.js
index 5bf765f..07ef71f 100644
--- a/front_end/inline_editor/CSSShadowEditor.js
+++ b/front_end/inline_editor/CSSShadowEditor.js
@@ -68,7 +68,7 @@
    * @return {!Element}
    */
   _createSlider(field) {
-    const slider = UI.createSliderLabel(0, InlineEditor.CSSShadowEditor.maxRange, -1);
+    const slider = UI.createSlider(0, InlineEditor.CSSShadowEditor.maxRange, -1);
     slider.addEventListener('input', this._onSliderInput.bind(this), false);
     field.appendChild(slider);
     return slider;
diff --git a/front_end/inline_editor/ColorSwatch.js b/front_end/inline_editor/ColorSwatch.js
index 5f5eb0b..2dfc68a 100644
--- a/front_end/inline_editor/ColorSwatch.js
+++ b/front_end/inline_editor/ColorSwatch.js
@@ -7,6 +7,17 @@
 InlineEditor.ColorSwatch = class extends HTMLSpanElement {
   constructor() {
     super();
+    const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css');
+
+    this._iconElement = root.createChild('span', 'color-swatch');
+    this._iconElement.title = Common.UIString('Shift-click to change color format');
+    this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner');
+    this._swatchInner.addEventListener('dblclick', e => e.consume(), false);
+    this._swatchInner.addEventListener('mousedown', e => e.consume(), false);
+    this._swatchInner.addEventListener('click', this._handleClick.bind(this), true);
+
+    root.createChild('slot');
+    this._colorValueElement = this.createChild('span');
   }
 
   /**
@@ -15,11 +26,11 @@
   static create() {
     if (!InlineEditor.ColorSwatch._constructor) {
       InlineEditor.ColorSwatch._constructor =
-          UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch.prototype);
+          UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch);
     }
 
 
-    return /** @type {!InlineEditor.ColorSwatch} */ (new InlineEditor.ColorSwatch._constructor());
+    return /** @type {!InlineEditor.ColorSwatch} */ (InlineEditor.ColorSwatch._constructor());
   }
 
   /**
@@ -134,23 +145,6 @@
   }
 
   /**
-   * @override
-   */
-  createdCallback() {
-    const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css');
-
-    this._iconElement = root.createChild('span', 'color-swatch');
-    this._iconElement.title = Common.UIString('Shift-click to change color format');
-    this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner');
-    this._swatchInner.addEventListener('dblclick', e => e.consume(), false);
-    this._swatchInner.addEventListener('mousedown', e => e.consume(), false);
-    this._swatchInner.addEventListener('click', this._handleClick.bind(this), true);
-
-    root.createChild('content');
-    this._colorValueElement = this.createChild('span');
-  }
-
-  /**
    * @param {!Event} event
    */
   _handleClick(event) {
@@ -168,6 +162,11 @@
 InlineEditor.BezierSwatch = class extends HTMLSpanElement {
   constructor() {
     super();
+    const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css');
+    this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon');
+    root.appendChild(this._iconElement);
+    this._textElement = this.createChild('span');
+    root.createChild('slot');
   }
 
   /**
@@ -176,11 +175,11 @@
   static create() {
     if (!InlineEditor.BezierSwatch._constructor) {
       InlineEditor.BezierSwatch._constructor =
-          UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch.prototype);
+          UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch);
     }
 
 
-    return /** @type {!InlineEditor.BezierSwatch} */ (new InlineEditor.BezierSwatch._constructor());
+    return /** @type {!InlineEditor.BezierSwatch} */ (InlineEditor.BezierSwatch._constructor());
   }
 
   /**
@@ -210,17 +209,6 @@
   iconElement() {
     return this._iconElement;
   }
-
-  /**
-   * @override
-   */
-  createdCallback() {
-    const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css');
-    this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon');
-    root.appendChild(this._iconElement);
-    this._textElement = this.createChild('span');
-    root.createChild('content');
-  }
 };
 
 /**
@@ -229,6 +217,11 @@
 InlineEditor.CSSShadowSwatch = class extends HTMLSpanElement {
   constructor() {
     super();
+    const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css');
+    this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon');
+    root.appendChild(this._iconElement);
+    root.createChild('slot');
+    this._contentElement = this.createChild('span');
   }
 
   /**
@@ -237,10 +230,10 @@
   static create() {
     if (!InlineEditor.CSSShadowSwatch._constructor) {
       InlineEditor.CSSShadowSwatch._constructor =
-          UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch.prototype);
+          UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch);
     }
 
-    return /** @type {!InlineEditor.CSSShadowSwatch} */ (new InlineEditor.CSSShadowSwatch._constructor());
+    return /** @type {!InlineEditor.CSSShadowSwatch} */ (InlineEditor.CSSShadowSwatch._constructor());
   }
 
   /**
@@ -290,15 +283,4 @@
   colorSwatch() {
     return this._colorSwatch;
   }
-
-  /**
-   * @override
-   */
-  createdCallback() {
-    const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css');
-    this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon');
-    root.appendChild(this._iconElement);
-    root.createChild('content');
-    this._contentElement = this.createChild('span');
-  }
 };
diff --git a/front_end/inspector_main/renderingOptions.css b/front_end/inspector_main/renderingOptions.css
index 77eeb51..b478b44 100644
--- a/front_end/inspector_main/renderingOptions.css
+++ b/front_end/inspector_main/renderingOptions.css
@@ -8,7 +8,7 @@
     padding: 12px;
  }
 
-label {
+[is=dt-checkbox] {
     margin: 0px 0px 10px 0px;
     flex: none;
 }
diff --git a/front_end/layers_test_runner/LayersTestRunner.js b/front_end/layers_test_runner/LayersTestRunner.js
index d5c69d7..20e51c3 100644
--- a/front_end/layers_test_runner/LayersTestRunner.js
+++ b/front_end/layers_test_runner/LayersTestRunner.js
@@ -106,7 +106,8 @@
     screenY: totalOffset.top - element.scrollTop + offsetY,
     clientX: totalOffset.left + offsetX,
     clientY: totalOffset.top + offsetY,
-    button: button
+    button: button,
+    composed: true
   };
 
   if (eventType === 'mouseout') {
diff --git a/front_end/network/RequestHeadersView.js b/front_end/network/RequestHeadersView.js
index b69345c..03f7668 100644
--- a/front_end/network/RequestHeadersView.js
+++ b/front_end/network/RequestHeadersView.js
@@ -379,7 +379,7 @@
       statusCodeFragment.createChild('div', 'header-name').textContent = Common.UIString('Status Code') + ': ';
       statusCodeFragment.createChild('span', 'header-separator');
 
-      const statusCodeImage = statusCodeFragment.createChild('label', 'resource-status-image', 'dt-icon-label');
+      const statusCodeImage = statusCodeFragment.createChild('span', 'resource-status-image', 'dt-icon-label');
       statusCodeImage.title = this._request.statusCode + ' ' + this._request.statusText;
 
       if (this._request.statusCode < 300 || this._request.statusCode === 304)
@@ -442,7 +442,7 @@
     if (provisionalHeaders) {
       const cautionText = Common.UIString('Provisional headers are shown');
       const cautionFragment = createDocumentFragment();
-      cautionFragment.createChild('label', '', 'dt-icon-label').type = 'smallicon-warning';
+      cautionFragment.createChild('span', '', 'dt-icon-label').type = 'smallicon-warning';
       cautionFragment.createChild('div', 'caution').textContent = cautionText;
       const cautionTreeElement = new UI.TreeElement(cautionFragment);
       cautionTreeElement.selectable = false;
diff --git a/front_end/network/networkConfigView.css b/front_end/network/networkConfigView.css
index 6c5ede0..df86aa2 100644
--- a/front_end/network/networkConfigView.css
+++ b/front_end/network/networkConfigView.css
@@ -57,11 +57,11 @@
     line-height: 20px;
 }
 
-.network-config-ua label[is="dt-radio"].checked > * {
+.network-config-ua span[is="dt-radio"].checked > * {
     display: none
 }
 
-.network-config-ua input:not(.dt-radio-button) {
+.network-config-ua input {
     display: block;
     width: calc(100% - 20px);
 }
@@ -79,7 +79,7 @@
     max-width: 250px;
 }
 
-.network-config-ua label[is="dt-radio"] {
+.network-config-ua span[is="dt-radio"] {
     display: block;
 }
 
diff --git a/front_end/network/networkLogView.css b/front_end/network/networkLogView.css
index 2a1d831..eaeb07a 100644
--- a/front_end/network/networkLogView.css
+++ b/front_end/network/networkLogView.css
@@ -44,7 +44,7 @@
     overflow: hidden;
 }
 
-.network-summary-bar label[is=dt-icon-label] {
+.network-summary-bar span[is=dt-icon-label] {
     margin-right: 6px;
 }
 
diff --git a/front_end/object_ui/ObjectPropertiesSection.js b/front_end/object_ui/ObjectPropertiesSection.js
index 37c4edb..0f5acb8 100644
--- a/front_end/object_ui/ObjectPropertiesSection.js
+++ b/front_end/object_ui/ObjectPropertiesSection.js
@@ -432,7 +432,7 @@
    * @param {!Array.<!SDK.RemoteObjectProperty>=} extraProperties
    */
   constructor(object, linkifier, emptyPlaceholder, ignoreHasOwnProperty, extraProperties) {
-    const contentElement = createElement('content');
+    const contentElement = createElement('slot');
     super(contentElement);
 
     this._object = object;
diff --git a/front_end/object_ui/objectPropertiesSection.css b/front_end/object_ui/objectPropertiesSection.css
index c6bf2e4..89892c7 100644
--- a/front_end/object_ui/objectPropertiesSection.css
+++ b/front_end/object_ui/objectPropertiesSection.css
@@ -70,7 +70,7 @@
     background: none;
 }
 
-.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] ::content > *,
+.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] ::slotted(*),
 .tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] .name-and-value {
     background: var(--focus-bg-color);
     border-radius: 2px;
diff --git a/front_end/profiler/profilesPanel.css b/front_end/profiler/profilesPanel.css
index a44bd15..4849d7b 100644
--- a/front_end/profiler/profilesPanel.css
+++ b/front_end/profiler/profilesPanel.css
@@ -128,7 +128,7 @@
     margin: 0 0 5px 0;
 }
 
-.profile-launcher-view-content label {
+.profile-launcher-view-content [is=dt-radio] {
     font-size: 13px;
 }
 
@@ -165,7 +165,7 @@
     margin-left: 22px;
 }
 
-.profile-launcher-view-content p label {
+.profile-launcher-view-content p [is=dt-checkbox] {
     display: flex;
 }
 
@@ -190,7 +190,7 @@
     to { background-color: rgba(255, 255, 120, 0); }
 }
 
-.profile-canvas-decoration label[is=dt-icon-label] {
+.profile-canvas-decoration span[is=dt-icon-label] {
     margin-right: 4px;
 }
 
diff --git a/front_end/resources/ApplicationCacheItemsView.js b/front_end/resources/ApplicationCacheItemsView.js
index 9bee1db..f83a6b6 100644
--- a/front_end/resources/ApplicationCacheItemsView.js
+++ b/front_end/resources/ApplicationCacheItemsView.js
@@ -38,9 +38,9 @@
     this._deleteButton.setVisible(false);
     this._deleteButton.addEventListener(UI.ToolbarButton.Events.Click, this._deleteButtonClicked, this);
 
-    this._connectivityIcon = createElement('label', 'dt-icon-label');
+    this._connectivityIcon = createElement('span', 'dt-icon-label');
     this._connectivityIcon.style.margin = '0 2px 0 5px';
-    this._statusIcon = createElement('label', 'dt-icon-label');
+    this._statusIcon = createElement('span', 'dt-icon-label');
     this._statusIcon.style.margin = '0 2px 0 5px';
 
     this._frameId = frameId;
diff --git a/front_end/security/SecurityPanel.js b/front_end/security/SecurityPanel.js
index 7318c75..7306cf3 100644
--- a/front_end/security/SecurityPanel.js
+++ b/front_end/security/SecurityPanel.js
@@ -79,7 +79,7 @@
       return text;
     }
 
-    const highlightedUrl = createElement('span', 'url-text');
+    const highlightedUrl = createElement('span');
 
     const scheme = url.substr(0, index);
     const content = url.substr(index + schemeSeparator.length);
diff --git a/front_end/settings/settingsScreen.css b/front_end/settings/settingsScreen.css
index 47c80a7..9989041 100644
--- a/front_end/settings/settingsScreen.css
+++ b/front_end/settings/settingsScreen.css
@@ -211,15 +211,11 @@
     margin-left: 10px;
 }
 
-.settings-indent-labels label {
-    padding-left: 10px;
-}
-
 .settings-experiment-hidden {
     display: none;
 }
 
-.settings-experiment-hidden label {
+.settings-experiment-hidden [is=dt-checkbox] {
     background-color: #ddd;
 }
 
diff --git a/front_end/sources/UISourceCodeFrame.js b/front_end/sources/UISourceCodeFrame.js
index 47cb6bc..0801439 100644
--- a/front_end/sources/UISourceCodeFrame.js
+++ b/front_end/sources/UISourceCodeFrame.js
@@ -584,7 +584,7 @@
     this._icon = this.element.createChild('label', '', 'dt-icon-label');
     this._icon.type = Sources.UISourceCodeFrame._iconClassPerLevel[message.level()];
     this._repeatCountElement =
-        this.element.createChild('label', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble');
+        this.element.createChild('span', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble');
     this._repeatCountElement.type = Sources.UISourceCodeFrame._bubbleTypePerLevel[message.level()];
     const linesContainer = this.element.createChild('div');
     const lines = this._message.text().split('\n');
@@ -636,7 +636,7 @@
     this._decoration = createElementWithClass('div', 'text-editor-line-decoration');
     this._decoration._messageBucket = this;
     this._wave = this._decoration.createChild('div', 'text-editor-line-decoration-wave');
-    this._icon = this._wave.createChild('label', 'text-editor-line-decoration-icon', 'dt-icon-label');
+    this._icon = this._wave.createChild('span', 'text-editor-line-decoration-icon', 'dt-icon-label');
     /** @type {?number} */
     this._decorationStartColumn = null;
 
diff --git a/front_end/sources/sourcesPanel.css b/front_end/sources/sourcesPanel.css
index 4b49787..17d4d4a 100644
--- a/front_end/sources/sourcesPanel.css
+++ b/front_end/sources/sourcesPanel.css
@@ -50,7 +50,7 @@
     margin-top: 0;
 }
 
-.scripts-debug-toolbar-drawer > label {
+.scripts-debug-toolbar-drawer > [is=dt-checkbox] {
     display: flex;
     padding-left: 3px;
     height: 28px;
diff --git a/front_end/timeline/TimelineHistoryManager.js b/front_end/timeline/TimelineHistoryManager.js
index 7bd3fc0..ecd5308 100644
--- a/front_end/timeline/TimelineHistoryManager.js
+++ b/front_end/timeline/TimelineHistoryManager.js
@@ -426,12 +426,11 @@
    * @param {!UI.Action} action
    */
   constructor(action) {
-    super(createElementWithClass('button', 'dropdown-button'));
-    const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'timeline/historyToolbarButton.css');
-
-    this._contentElement = shadowRoot.createChild('span', 'content');
+    super(createElementWithClass('button', 'history-dropdown-button'));
+    UI.appendStyle(this.element, 'timeline/historyToolbarButton.css');
+    this._contentElement = this.element.createChild('span', 'content');
     const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
-    shadowRoot.appendChild(dropdownArrowIcon);
+    this.element.appendChild(dropdownArrowIcon);
     this.element.addEventListener('click', () => void action.execute(), false);
     this.setEnabled(action.enabled());
     action.addEventListener(UI.Action.Events.Enabled, event => this.setEnabled(/** @type {boolean} */ (event.data)));
diff --git a/front_end/timeline/historyToolbarButton.css b/front_end/timeline/historyToolbarButton.css
index f66188b..0259abf 100644
--- a/front_end/timeline/historyToolbarButton.css
+++ b/front_end/timeline/historyToolbarButton.css
@@ -4,18 +4,18 @@
  * found in the LICENSE file.
  */
 
-:host {
+.history-dropdown-button {
   width: 160px;
   height: 26px;
   text-align: left;
   display: flex;
 }
 
-:host([disabled]) {
+.history-dropdown-button[disabled] {
   opacity: .5;
 }
 
-.content {
+.history-dropdown-button > .content {
   padding-right: 5px;
   overflow: hidden;
   text-overflow: ellipsis;
diff --git a/front_end/ui/HistoryInput.js b/front_end/ui/HistoryInput.js
index b5cefa7..81784fc 100644
--- a/front_end/ui/HistoryInput.js
+++ b/front_end/ui/HistoryInput.js
@@ -5,24 +5,21 @@
  * @unrestricted
  */
 UI.HistoryInput = class extends HTMLInputElement {
+  constructor() {
+    super();
+    this._history = [''];
+    this._historyPosition = 0;
+    this.addEventListener('keydown', this._onKeyDown.bind(this), false);
+    this.addEventListener('input', this._onInput.bind(this), false);
+  }
   /**
    * @return {!UI.HistoryInput}
    */
   static create() {
     if (!UI.HistoryInput._constructor)
-      UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput.prototype);
+      UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput);
 
-    return /** @type {!UI.HistoryInput} */ (new UI.HistoryInput._constructor());
-  }
-
-  /**
-   * @override
-   */
-  createdCallback() {
-    this._history = [''];
-    this._historyPosition = 0;
-    this.addEventListener('keydown', this._onKeyDown.bind(this), false);
-    this.addEventListener('input', this._onInput.bind(this), false);
+    return /** @type {!UI.HistoryInput} */ (UI.HistoryInput._constructor());
   }
 
   /**
diff --git a/front_end/ui/Icon.js b/front_end/ui/Icon.js
index 11b6d98..9d1fd5e 100644
--- a/front_end/ui/Icon.js
+++ b/front_end/ui/Icon.js
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/**
- * @constructor
- * @extends {HTMLSpanElement}
- */
 UI.Icon = class extends HTMLSpanElement {
   constructor() {
     super();
-    throw new Error('icon must be created via factory method.');
+    /** @type {?UI.Icon.Descriptor} */
+    this._descriptor = null;
+    /** @type {?UI.Icon.SpriteSheet} */
+    this._spriteSheet = null;
+    /** @type {string} */
+    this._iconType = '';
   }
 
   /**
@@ -19,9 +20,9 @@
    */
   static create(iconType, className) {
     if (!UI.Icon._constructor)
-      UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon.prototype);
+      UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon);
 
-    const icon = /** @type {!UI.Icon} */ (new UI.Icon._constructor());
+    const icon = /** @type {!UI.Icon} */ (UI.Icon._constructor());
     if (className)
       icon.className = className;
     if (iconType)
@@ -30,18 +31,6 @@
   }
 
   /**
-   * @override
-   */
-  createdCallback() {
-    /** @type {?UI.Icon.Descriptor} */
-    this._descriptor = null;
-    /** @type {?UI.Icon.SpriteSheet} */
-    this._spriteSheet = null;
-    /** @type {string} */
-    this._iconType = '';
-  }
-
-  /**
    * @param {string} iconType
    */
   setIconType(iconType) {
diff --git a/front_end/ui/ListWidget.js b/front_end/ui/ListWidget.js
index c11ae3a..0ba4777 100644
--- a/front_end/ui/ListWidget.js
+++ b/front_end/ui/ListWidget.js
@@ -9,12 +9,11 @@
    * @param {!UI.ListWidget.Delegate<T>} delegate
    */
   constructor(delegate) {
-    super(true);
+    super(true, true /* delegatesFocus */);
     this.registerRequiredCSS('ui/listWidget.css');
     this._delegate = delegate;
 
     this._list = this.contentElement.createChild('div', 'list');
-    this.element.tabIndex = -1;
 
     this._lastSeparator = false;
     /** @type {?UI.ElementFocusRestorer} */
diff --git a/front_end/ui/SearchableView.js b/front_end/ui/SearchableView.js
index a0fa78f..f03af0f 100644
--- a/front_end/ui/SearchableView.js
+++ b/front_end/ui/SearchableView.js
@@ -46,7 +46,7 @@
     this._setting = settingName ? Common.settings.createSetting(settingName, {}) : null;
     this._replaceable = false;
 
-    this.contentElement.createChild('content');
+    this.contentElement.createChild('slot');
     this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
     this._footerElementContainer.style.order = 100;
     this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
diff --git a/front_end/ui/SoftDropDown.js b/front_end/ui/SoftDropDown.js
index 88e8e97..6d21c34 100644
--- a/front_end/ui/SoftDropDown.js
+++ b/front_end/ui/SoftDropDown.js
@@ -16,10 +16,10 @@
     this._model = model;
 
     this.element = createElementWithClass('button', 'soft-dropdown');
-    const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/softDropDownButton.css');
-    this._titleElement = shadowRoot.createChild('span', 'title');
+    UI.appendStyle(this.element, 'ui/softDropDownButton.css');
+    this._titleElement = this.element.createChild('span', 'title');
     const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
-    shadowRoot.appendChild(dropdownArrowIcon);
+    this.element.appendChild(dropdownArrowIcon);
 
     this._glassPane = new UI.GlassPane();
     this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin);
diff --git a/front_end/ui/SplitWidget.js b/front_end/ui/SplitWidget.js
index f0b55ed..950b230 100644
--- a/front_end/ui/SplitWidget.js
+++ b/front_end/ui/SplitWidget.js
@@ -46,10 +46,10 @@
     this.contentElement.classList.add('shadow-split-widget');
     this._mainElement =
         this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-main vbox');
-    this._mainElement.createChild('content').select = '.insertion-point-main';
+    this._mainElement.createChild('slot').name = 'insertion-point-main';
     this._sidebarElement =
         this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-sidebar vbox');
-    this._sidebarElement.createChild('content').select = '.insertion-point-sidebar';
+    this._sidebarElement.createChild('slot').name = 'insertion-point-sidebar';
     this._resizerElement = this.contentElement.createChild('div', 'shadow-split-widget-resizer');
     this._resizerElementSize = null;
 
@@ -165,8 +165,7 @@
       this._mainWidget.detach();
     this._mainWidget = widget;
     if (widget) {
-      widget.element.classList.add('insertion-point-main');
-      widget.element.classList.remove('insertion-point-sidebar');
+      widget.element.slot = 'insertion-point-main';
       if (this._showMode === UI.SplitWidget.ShowMode.OnlyMain || this._showMode === UI.SplitWidget.ShowMode.Both)
         widget.show(this.element);
     }
@@ -184,8 +183,7 @@
       this._sidebarWidget.detach();
     this._sidebarWidget = widget;
     if (widget) {
-      widget.element.classList.add('insertion-point-sidebar');
-      widget.element.classList.remove('insertion-point-main');
+      widget.element.slot = 'insertion-point-sidebar';
       if (this._showMode === UI.SplitWidget.ShowMode.OnlySidebar || this._showMode === UI.SplitWidget.ShowMode.Both)
         widget.show(this.element);
     }
diff --git a/front_end/ui/TabbedPane.js b/front_end/ui/TabbedPane.js
index 3a64985..f51f82d 100644
--- a/front_end/ui/TabbedPane.js
+++ b/front_end/ui/TabbedPane.js
@@ -46,7 +46,7 @@
     this._tabsElement.addEventListener('keydown', this._keyDown.bind(this), false);
     this._contentElement = this.contentElement.createChild('div', 'tabbed-pane-content');
     this._contentElement.setAttribute('role', 'tabpanel');
-    this._contentElement.createChild('content');
+    this._contentElement.createChild('slot');
     /** @type {!Array.<!UI.TabbedPaneTab>} */
     this._tabs = [];
     /** @type {!Array.<!UI.TabbedPaneTab>} */
diff --git a/front_end/ui/Toolbar.js b/front_end/ui/Toolbar.js
index bd54790..3495310 100644
--- a/front_end/ui/Toolbar.js
+++ b/front_end/ui/Toolbar.js
@@ -45,7 +45,7 @@
     this._enabled = true;
     this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/toolbar.css');
     this._contentElement = this._shadowRoot.createChild('div', 'toolbar-shadow');
-    this._insertionPoint = this._contentElement.createChild('content');
+    this._insertionPoint = this._contentElement.createChild('slot');
   }
 
   /**
@@ -277,7 +277,7 @@
       delete item._toolbar;
     this._items = [];
     this._contentElement.removeChildren();
-    this._insertionPoint = this._contentElement.createChild('content');
+    this._insertionPoint = this._contentElement.createChild('slot');
   }
 
   /**
diff --git a/front_end/ui/Tooltip.js b/front_end/ui/Tooltip.js
index a8034a0..253f22f 100644
--- a/front_end/ui/Tooltip.js
+++ b/front_end/ui/Tooltip.js
@@ -54,7 +54,7 @@
    */
   _mouseMove(event) {
     const mouseEvent = /** @type {!MouseEvent} */ (event);
-    const path = mouseEvent.path;
+    const path = mouseEvent.composedPath();
     if (!path || mouseEvent.buttons !== 0 || (mouseEvent.movementX === 0 && mouseEvent.movementY === 0))
       return;
 
@@ -63,7 +63,8 @@
 
     for (const element of path) {
       // The offsetParent is null when the element or an ancestor has 'display: none'.
-      if (element === this._anchorElement || (element.nodeName !== 'CONTENT' && element.offsetParent === null)) {
+      if (!(element instanceof Element) || element === this._anchorElement ||
+          (element.nodeName !== 'SLOT' && element.offsetParent === null)) {
         return;
       } else if (element[UI.Tooltip._symbol]) {
         this._show(element, mouseEvent);
diff --git a/front_end/ui/UIUtils.js b/front_end/ui/UIUtils.js
index 45d2074..9820f1e 100644
--- a/front_end/ui/UIUtils.js
+++ b/front_end/ui/UIUtils.js
@@ -702,10 +702,11 @@
 /**
  * @param {!Element} element
  * @param {string=} cssFile
+ * @param {boolean=} delegatesFocus
  * @return {!DocumentFragment}
  */
-UI.createShadowRootWithCoreStyles = function(element, cssFile) {
-  const shadowRoot = element.createShadowRoot();
+UI.createShadowRootWithCoreStyles = function(element, cssFile, delegatesFocus) {
+  const shadowRoot = element.attachShadow({mode: 'open', delegatesFocus});
   UI._injectCoreStyles(shadowRoot);
   if (cssFile)
     UI.appendStyle(shadowRoot, cssFile);
@@ -1172,13 +1173,19 @@
 /**
  * @param {string} localName
  * @param {string} typeExtension
- * @param {!Object} prototype
+ * @param {function(new:HTMLElement, *)} definition
  * @return {function()}
  * @suppressGlobalPropertiesCheck
- * @template T
  */
-UI.registerCustomElement = function(localName, typeExtension, prototype) {
-  return document.registerElement(typeExtension, {prototype: Object.create(prototype), extends: localName});
+UI.registerCustomElement = function(localName, typeExtension, definition) {
+  self.customElements.define(typeExtension, class extends definition {
+    constructor() {
+      super();
+      // TODO(einbinder) convert to classes and custom element tags
+      this.setAttribute('is', typeExtension);
+    }
+  }, {extends: localName});
+  return () => createElement(localName, typeExtension);
 };
 
 /**
@@ -1221,10 +1228,10 @@
  * @return {!Element}
  */
 UI.createRadioLabel = function(name, title, checked) {
-  const element = createElement('label', 'dt-radio');
+  const element = createElement('span', 'dt-radio');
   element.radioElement.name = name;
   element.radioElement.checked = !!checked;
-  element.createTextChild(title);
+  element.labelElement.createTextChild(title);
   return element;
 };
 
@@ -1234,7 +1241,7 @@
  * @return {!Element}
  */
 UI.createLabel = function(title, iconClass) {
-  const element = createElement('label', 'dt-icon-label');
+  const element = createElement('span', 'dt-icon-label');
   element.createChild('span').textContent = title;
   element.type = iconClass;
   return element;
@@ -1246,8 +1253,8 @@
  * @param {number} max
  * @param {number} tabIndex
  */
-UI.createSliderLabel = function(min, max, tabIndex) {
-  const element = createElement('label', 'dt-slider');
+UI.createSlider = function(min, max, tabIndex) {
+  const element = createElement('span', 'dt-slider');
   element.sliderElement.min = min;
   element.sliderElement.max = max;
   element.sliderElement.step = 1;
@@ -1278,10 +1285,7 @@
   }
 };
 
-/**
- * @extends {HTMLLabelElement}
- */
-UI.CheckboxLabel = class extends HTMLLabelElement {
+UI.CheckboxLabel = class extends HTMLSpanElement {
   constructor() {
     super();
     /** @type {!DocumentFragment} */
@@ -1290,13 +1294,6 @@
     this.checkboxElement;
     /** @type {!Element} */
     this.textElement;
-    throw new Error('Checkbox must be created via factory method.');
-  }
-
-  /**
-   * @override
-   */
-  createdCallback() {
     UI.CheckboxLabel._lastId = (UI.CheckboxLabel._lastId || 0) + 1;
     const id = 'ui-checkbox-label' + UI.CheckboxLabel._lastId;
     this._shadowRoot = UI.createShadowRootWithCoreStyles(this, 'ui/checkboxTextLabel.css');
@@ -1305,7 +1302,7 @@
     this.checkboxElement.setAttribute('id', id);
     this.textElement = this._shadowRoot.createChild('label', 'dt-checkbox-text');
     this.textElement.setAttribute('for', id);
-    this._shadowRoot.createChild('content');
+    this._shadowRoot.createChild('slot');
   }
 
   /**
@@ -1316,8 +1313,8 @@
    */
   static create(title, checked, subtitle) {
     if (!UI.CheckboxLabel._constructor)
-      UI.CheckboxLabel._constructor = UI.registerCustomElement('label', 'dt-checkbox', UI.CheckboxLabel.prototype);
-    const element = /** @type {!UI.CheckboxLabel} */ (new UI.CheckboxLabel._constructor());
+      UI.CheckboxLabel._constructor = UI.registerCustomElement('span', 'dt-checkbox', UI.CheckboxLabel);
+    const element = /** @type {!UI.CheckboxLabel} */ (UI.CheckboxLabel._constructor());
     element.checkboxElement.checked = !!checked;
     if (title !== undefined) {
       element.textElement.textContent = title;
@@ -1358,139 +1355,124 @@
 };
 
 (function() {
-  UI.registerCustomElement('label', 'dt-radio', {
-    /**
-     * @this {Element}
-     */
-    createdCallback: function() {
-      this.radioElement = this.createChild('input', 'dt-radio-button');
-      this.radioElement.type = 'radio';
-      const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css');
-      root.createChild('content').select = '.dt-radio-button';
-      root.createChild('content');
-      this.addEventListener('click', radioClickHandler, false);
-    },
+let labelId = 0;
+UI.registerCustomElement('span', 'dt-radio', class extends HTMLSpanElement {
+  constructor() {
+    super();
+    this.radioElement = this.createChild('input', 'dt-radio-button');
+    this.labelElement = this.createChild('label');
 
-    __proto__: HTMLLabelElement.prototype
-  });
+    const id = 'dt-radio-button-id' + (++labelId);
+    this.radioElement.id = id;
+    this.radioElement.type = 'radio';
+    this.labelElement.htmlFor = id;
+    const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css');
+    root.createChild('slot');
+    this.addEventListener('click', radioClickHandler, false);
+  }
+});
 
-  /**
+/**
    * @param {!Event} event
    * @suppressReceiverCheck
    * @this {Element}
    */
-  function radioClickHandler(event) {
-    if (this.radioElement.checked || this.radioElement.disabled)
-      return;
-    this.radioElement.checked = true;
-    this.radioElement.dispatchEvent(new Event('change'));
+function radioClickHandler(event) {
+  if (this.radioElement.checked || this.radioElement.disabled)
+    return;
+  this.radioElement.checked = true;
+  this.radioElement.dispatchEvent(new Event('change'));
+}
+
+UI.registerCustomElement('span', 'dt-icon-label', class extends HTMLSpanElement {
+  constructor() {
+    super();
+    const root = UI.createShadowRootWithCoreStyles(this);
+    this._iconElement = UI.Icon.create();
+    this._iconElement.style.setProperty('margin-right', '4px');
+    root.appendChild(this._iconElement);
+    root.createChild('slot');
   }
 
-  UI.registerCustomElement('label', 'dt-icon-label', {
-    /**
-     * @this {Element}
-     */
-    createdCallback: function() {
-      const root = UI.createShadowRootWithCoreStyles(this);
-      this._iconElement = UI.Icon.create();
-      this._iconElement.style.setProperty('margin-right', '4px');
-      root.appendChild(this._iconElement);
-      root.createChild('content');
-    },
-
-    /**
+  /**
      * @param {string} type
      * @this {Element}
      */
-    set type(type) {
-      this._iconElement.setIconType(type);
-    },
+  set type(type) {
+    this._iconElement.setIconType(type);
+  }
+});
 
-    __proto__: HTMLLabelElement.prototype
-  });
+UI.registerCustomElement('span', 'dt-slider', class extends HTMLSpanElement {
+  constructor() {
+    super();
+    const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css');
+    this.sliderElement = createElementWithClass('input', 'dt-range-input');
+    this.sliderElement.type = 'range';
+    root.appendChild(this.sliderElement);
+  }
 
-  UI.registerCustomElement('label', 'dt-slider', {
-    /**
-     * @this {Element}
-     */
-    createdCallback: function() {
-      const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css');
-      this.sliderElement = createElementWithClass('input', 'dt-range-input');
-      this.sliderElement.type = 'range';
-      root.appendChild(this.sliderElement);
-    },
-
-    /**
+  /**
      * @param {number} amount
      * @this {Element}
      */
-    set value(amount) {
-      this.sliderElement.value = amount;
-    },
+  set value(amount) {
+    this.sliderElement.value = amount;
+  }
 
-    /**
+  /**
      * @this {Element}
      */
-    get value() {
-      return this.sliderElement.value;
-    },
+  get value() {
+    return this.sliderElement.value;
+  }
+});
 
-    __proto__: HTMLLabelElement.prototype
-  });
+UI.registerCustomElement('span', 'dt-small-bubble', class extends HTMLSpanElement {
+  constructor() {
+    super();
+    const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css');
+    this._textElement = root.createChild('div');
+    this._textElement.className = 'info';
+    this._textElement.createChild('slot');
+  }
 
-  UI.registerCustomElement('label', 'dt-small-bubble', {
-    /**
-     * @this {Element}
-     */
-    createdCallback: function() {
-      const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css');
-      this._textElement = root.createChild('div');
-      this._textElement.className = 'info';
-      this._textElement.createChild('content');
-    },
-
-    /**
+  /**
      * @param {string} type
      * @this {Element}
      */
-    set type(type) {
-      this._textElement.className = type;
-    },
+  set type(type) {
+    this._textElement.className = type;
+  }
+});
 
-    __proto__: HTMLLabelElement.prototype
-  });
+UI.registerCustomElement('div', 'dt-close-button', class extends HTMLDivElement {
+  constructor() {
+    super();
+    const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css');
+    this._buttonElement = root.createChild('div', 'close-button');
+    const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon');
+    this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon');
+    this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon');
+    this._buttonElement.appendChild(regularIcon);
+    this._buttonElement.appendChild(this._hoverIcon);
+    this._buttonElement.appendChild(this._activeIcon);
+  }
 
-  UI.registerCustomElement('div', 'dt-close-button', {
-    /**
-     * @this {Element}
-     */
-    createdCallback: function() {
-      const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css');
-      this._buttonElement = root.createChild('div', 'close-button');
-      const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon');
-      this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon');
-      this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon');
-      this._buttonElement.appendChild(regularIcon);
-      this._buttonElement.appendChild(this._hoverIcon);
-      this._buttonElement.appendChild(this._activeIcon);
-    },
-
-    /**
+  /**
      * @param {boolean} gray
      * @this {Element}
      */
-    set gray(gray) {
-      if (gray) {
-        this._hoverIcon.setIconType('mediumicon-gray-cross-hover');
-        this._activeIcon.setIconType('mediumicon-gray-cross-active');
-      } else {
-        this._hoverIcon.setIconType('mediumicon-red-cross-hover');
-        this._activeIcon.setIconType('mediumicon-red-cross-active');
-      }
-    },
-
-    __proto__: HTMLDivElement.prototype
-  });
+  set gray(gray) {
+    if (gray) {
+      this._hoverIcon.setIconType('mediumicon-gray-cross-hover');
+      this._activeIcon.setIconType('mediumicon-gray-cross-active');
+    } else {
+      this._hoverIcon.setIconType('mediumicon-red-cross-hover');
+      this._activeIcon.setIconType('mediumicon-red-cross-active');
+    }
+  }
+});
 })();
 
 /**
diff --git a/front_end/ui/View.js b/front_end/ui/View.js
index 222b8b7..0cf76ee 100644
--- a/front_end/ui/View.js
+++ b/front_end/ui/View.js
@@ -506,7 +506,7 @@
     this._titleElement.addEventListener('keydown', this._onTitleKeyDown.bind(this), false);
     this.contentElement.insertBefore(this._titleElement, this.contentElement.firstChild);
 
-    this.contentElement.createChild('content');
+    this.contentElement.createChild('slot');
     this._view = view;
     view[UI.ViewManager._ExpandableContainerWidget._symbol] = this;
   }
diff --git a/front_end/ui/Widget.js b/front_end/ui/Widget.js
index 861f157..611890d 100644
--- a/front_end/ui/Widget.js
+++ b/front_end/ui/Widget.js
@@ -30,13 +30,14 @@
 UI.Widget = class extends Common.Object {
   /**
    * @param {boolean=} isWebComponent
+   * @param {boolean=} delegatesFocus
    */
-  constructor(isWebComponent) {
+  constructor(isWebComponent, delegatesFocus) {
     super();
     this.contentElement = createElementWithClass('div', 'widget');
     if (isWebComponent) {
       this.element = createElementWithClass('div', 'vbox flex-auto');
-      this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element);
+      this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, undefined, delegatesFocus);
       this._shadowRoot.appendChild(this.contentElement);
     } else {
       this.element = this.contentElement;
@@ -599,9 +600,10 @@
 UI.VBox = class extends UI.Widget {
   /**
    * @param {boolean=} isWebComponent
+   * @param {boolean=} delegatesFocus
    */
-  constructor(isWebComponent) {
-    super(isWebComponent);
+  constructor(isWebComponent, delegatesFocus) {
+    super(isWebComponent, delegatesFocus);
     this.contentElement.classList.add('vbox');
   }
 
diff --git a/front_end/ui/filter.css b/front_end/ui/filter.css
index 025789e..b09df81 100644
--- a/front_end/ui/filter.css
+++ b/front_end/ui/filter.css
@@ -46,10 +46,6 @@
     align-items: center;
 }
 
-.filter-text-filter label {
-    margin: auto 0;
-}
-
 .filter-bitset-filter {
     padding: 2px;
     display: inline-flex;
@@ -116,7 +112,7 @@
     position: relative;
 }
 
-.filter-checkbox-filter > label {
+.filter-checkbox-filter > [is=dt-checkbox] {
     display: flex;
     margin: auto 0;
 }
diff --git a/front_end/ui/inspectorCommon.css b/front_end/ui/inspectorCommon.css
index e5fd320..365d09a 100644
--- a/front_end/ui/inspectorCommon.css
+++ b/front_end/ui/inspectorCommon.css
@@ -310,7 +310,7 @@
     white-space: nowrap;
 }
 
-label[is=dt-icon-label] {
+span[is=dt-icon-label] {
     flex: none;
 }
 
diff --git a/front_end/ui/radioButton.css b/front_end/ui/radioButton.css
index 47f4775..cadf3a7 100644
--- a/front_end/ui/radioButton.css
+++ b/front_end/ui/radioButton.css
@@ -4,7 +4,7 @@
  * found in the LICENSE file.
  */
 
-::content .dt-radio-button {
+::slotted(input.dt-radio-button) {
     height: 17px;
     width: 17px;
     min-width: 17px;
@@ -16,16 +16,16 @@
     margin: 0 5px 5px 0;
 }
 
-::content .dt-radio-button:active:not(:disabled) {
+::slotted(input.dt-radio-button:active:not(:disabled)) {
     background-image: linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239));
 }
 
-::content .dt-radio-button:checked {
+::slotted(input.dt-radio-button:checked) {
     background: url(Images/radioDot.png) center no-repeat,
                 linear-gradient(to bottom, rgb(252, 252, 252), rgb(223, 223, 223));
 }
 
-::content .dt-radio-button:checked:active {
+::slotted(input.dt-radio-button:checked:active) {
     background: url(Images/radioDot.png) center no-repeat,
                 linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239));
 }
diff --git a/front_end/ui/softDropDownButton.css b/front_end/ui/softDropDownButton.css
index 3812ef1..2270d27 100644
--- a/front_end/ui/softDropDownButton.css
+++ b/front_end/ui/softDropDownButton.css
@@ -3,7 +3,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-:host {
+button.soft-dropdown {
     height: 26px;
     text-align: left;
     position: relative;
@@ -11,18 +11,18 @@
     background: none;
 }
 
-:host([disabled]) {
+button.soft-dropdown[disabled] {
     opacity: .5;
 }
 
-:host .title {
+button.soft-dropdown > .title {
     padding-right: 5px;
     width: 120px;
     overflow: hidden;
     text-overflow: ellipsis;
 }
 
-:host([data-keyboard-focus="true"]:focus)::before {
+button.soft-dropdown[data-keyboard-focus="true"]:focus::before {
     content: "";
     position: absolute;
     top: 2px;