wpt / css / css-shadow / shadow-host-style-sharing.html

Status: FAIL | Duration: 49ms | Subtests: 0/6 | Open test on wpt.live | wpt.fyi

Data from commit:
a50cb89 wpt: run reference-named files which are themselves tests (#836) (2026-09-03)

SubtestStatusMessage
Different CascadeData must block sharing despite being same element typeFAILCSSStyleSheet is not defined
Same :host rules but different inherited stylesFAILCSSStyleSheet is not defined
:host with class selector should not share across different classesFAILCSSStyleSheet is not defined
:host with attribute selector should not share across different attributesFAILCSSStyleSheet is not defined
Same CascadeData but different inline styles should not shareFAILCSSStyleSheet is not defined
Same :host rules but different CascadeData should prevent sharingFAILCSSStyleSheet is not defined

/css/css-shadow/shadow-host-style-sharing.html

<!DOCTYPE html>
<meta charset="utf-8">
<title>Shadow Host Style Sharing Tests</title>
<link rel="help" href="https://drafts.csswg.org/css-shadow/#host-selector">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<div id="container"></div>

<script>
const container = document.getElementById('container');

function cleanup() {
  container.innerHTML = '';
}

// Test 1: Different :host rules in different stylesheets
test(() => {
  cleanup();

  const redSheet = new CSSStyleSheet();
  redSheet.replaceSync(':host { color: rgb(255, 0, 0); }');

  const blueSheet = new CSSStyleSheet();
  blueSheet.replaceSync(':host { color: rgb(0, 0, 255); }');

  let useRed = true;

  class DynamicHost extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: 'open' });
      shadow.innerHTML = '<div>content</div>';
      shadow.adoptedStyleSheets = [useRed ? redSheet : blueSheet];
    }
  }
  customElements.define('dynamic-host-1', DynamicHost);

  const parent = document.createElement('div');

  // Create siblings: first 10 with red sheet
  useRed = true;
  const redHosts = [];
  for (let i = 0; i < 10; i++) {
    const host = document.createElement('dynamic-host-1');
    redHosts.push(host);
    parent.appendChild(host);
  }

  // Then 1 with blue sheet as a sibling
  useRed = false;
  const blueHost = document.createElement('dynamic-host-1');
  parent.appendChild(blueHost);

  // Add to document and force style computation
  container.appendChild(parent);
  container.offsetHeight;

  assert_equals(getComputedStyle(blueHost).color, 'rgb(0, 0, 255)', 'Must be blue, not red');

  for (const host of redHosts) {
    assert_equals(getComputedStyle(host).color, 'rgb(255, 0, 0)', 'Must be red');
  }
}, 'Different CascadeData must block sharing despite being same element type');

// Test 2: Same :host rules, different inherited styles
test(() => {
  cleanup();

  const sharedSheet = new CSSStyleSheet();
  sharedSheet.replaceSync(':host { font-size: 20px; }');

  class SharedHost extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: 'open' });
      shadow.adoptedStyleSheets = [sharedSheet];
      shadow.innerHTML = '<span>content</span>';
    }
  }
  customElements.define('shared-host-2', SharedHost);

  const parent1 = document.createElement('div');
  parent1.style.color = 'rgb(255, 0, 0)';
  const host1 = document.createElement('shared-host-2');
  parent1.appendChild(host1);
  container.appendChild(parent1);

  const parent2 = document.createElement('div');
  parent2.style.color = 'rgb(0, 255, 0)';
  const host2 = document.createElement('shared-host-2');
  parent2.appendChild(host2);
  container.appendChild(parent2);

  assert_equals(getComputedStyle(host1).color, 'rgb(255, 0, 0)');
  assert_equals(getComputedStyle(host2).color, 'rgb(0, 255, 0)');
}, 'Same :host rules but different inherited styles');

// Test 3: :host with class selector
test(() => {
  cleanup();

  const classSheet = new CSSStyleSheet();
  classSheet.replaceSync(`
    :host(.active) { background-color: rgb(255, 0, 0); }
    :host(.inactive) { background-color: rgb(0, 0, 255); }
  `);

  class ClassHost extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: 'open' });
      shadow.adoptedStyleSheets = [classSheet];
      shadow.innerHTML = '<span>content</span>';
    }
  }
  customElements.define('class-host-3', ClassHost);

  const active = document.createElement('class-host-3');
  active.className = 'active';
  const inactive = document.createElement('class-host-3');
  inactive.className = 'inactive';

  container.appendChild(active);
  container.appendChild(inactive);

  assert_equals(getComputedStyle(active).backgroundColor, 'rgb(255, 0, 0)');
  assert_equals(getComputedStyle(inactive).backgroundColor, 'rgb(0, 0, 255)');
}, ':host with class selector should not share across different classes');

// Test 4: :host with attribute selector
test(() => {
  cleanup();

  const attrSheet = new CSSStyleSheet();
  attrSheet.replaceSync(`
    :host([data-theme="dark"]) { color: rgb(0, 0, 0); }
    :host([data-theme="light"]) { color: rgb(255, 255, 255); }
  `);

  class AttrHost extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: 'open' });
      shadow.adoptedStyleSheets = [attrSheet];
      shadow.innerHTML = '<span>content</span>';
    }
  }
  customElements.define('attr-host-4', AttrHost);

  const dark = document.createElement('attr-host-4');
  dark.setAttribute('data-theme', 'dark');
  const light = document.createElement('attr-host-4');
  light.setAttribute('data-theme', 'light');

  container.appendChild(dark);
  container.appendChild(light);

  assert_equals(getComputedStyle(dark).color, 'rgb(0, 0, 0)');
  assert_equals(getComputedStyle(light).color, 'rgb(255, 255, 255)');
}, ':host with attribute selector should not share across different attributes');

// Test 5: Same stylesheet, different inline styles
test(() => {
  cleanup();

  const sharedSheet = new CSSStyleSheet();
  sharedSheet.replaceSync(':host { display: block; }');

  class InlineHost extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: 'open' });
      shadow.adoptedStyleSheets = [sharedSheet];
      shadow.innerHTML = '<span>content</span>';
    }
  }
  customElements.define('inline-host-5', InlineHost);

  const host1 = document.createElement('inline-host-5');
  host1.style.color = 'rgb(255, 0, 0)';

  const host2 = document.createElement('inline-host-5');
  host2.style.color = 'rgb(0, 255, 0)';

  container.appendChild(host1);
  container.appendChild(host2);

  assert_equals(getComputedStyle(host1).color, 'rgb(255, 0, 0)');
  assert_equals(getComputedStyle(host2).color, 'rgb(0, 255, 0)');
}, 'Same CascadeData but different inline styles should not share');

// Test 6: Same :host rules but different shadow stylesheets
test(() => {
  cleanup();

  const sheetA = new CSSStyleSheet();
  sheetA.replaceSync(':host { color: rgb(255, 0, 0); }');

  const sheetB = new CSSStyleSheet();
  sheetB.replaceSync(':host { color: rgb(255, 0, 0); } span { font-weight: bold; }');

  let whichSheet = 'a';

  class SubtleHost extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: 'open' });
      shadow.adoptedStyleSheets = [whichSheet === 'a' ? sheetA : sheetB];
      shadow.innerHTML = '<span>content</span>';
    }
  }
  customElements.define('subtle-host-6', SubtleHost);

  whichSheet = 'a';
  const hostA = document.createElement('subtle-host-6');

  whichSheet = 'b';
  const hostB = document.createElement('subtle-host-6');

  container.appendChild(hostA);
  container.appendChild(hostB);

  assert_equals(getComputedStyle(hostA).color, 'rgb(255, 0, 0)');
  assert_equals(getComputedStyle(hostB).color, 'rgb(255, 0, 0)');
}, 'Same :host rules but different CascadeData should prevent sharing');
</script>