New issue
Advanced search Search tips

Issue 889514 link

Starred by 1 user

Issue metadata

Status: ExternalDependency
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 2
Type: Bug



Sign in to add a comment

.assignedNodes({flatten: true}) returns undefined

Reported by orstavi...@gmail.com, Sep 26

Issue description

UserAgent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.16 Safari/537.36

Steps to reproduce the problem:
<script>
  class TheMother extends HTMLElement {
    constructor(){
      super();
      this.attachShadow({mode: "open"});
      this.shadowRoot.innerHTML = "<the-son><slot></slot></the-son>";
    }
  }
  class TheFather extends HTMLElement {
    constructor(){
      super();
      this.attachShadow({mode: "open"});
      this.shadowRoot.innerHTML = "<the-son><slot>father decides</slot></the-son>";
    }
  }
  class TheSon extends HTMLElement {
    constructor(){
      super();
      this.attachShadow({mode: "open"});
      this.shadowRoot.innerHTML = "<b><slot>son decides</slot></b>";
    }
  }
  customElements.define("the-mother", TheMother); 
  customElements.define("the-father", TheFather); 
  customElements.define("the-son", TheSon);
</script>

#son <the-son id="son">God decides</the-son><hr>
#son2 <the-son id="son2"></the-son><hr>
#son3 <the-son id="son3"><slot>God again</slot></the-son><hr>
#son4 <the-son id="son4"><slot></slot></the-son><hr>
#pap <the-father id="pap">God decides</the-father><hr>
#pap2 <the-father id="pap2"></the-father><hr>
#pap3 <the-father id="pap3"><slot>God again</slot></the-father><hr>
#pap4 <the-father id="pap4"><slot></slot></the-father><hr>
#mom <the-mother id="mom">God decides</the-mother><hr>
#mom2 (????)<the-mother id="mom2"></the-mother><hr>
#mom3 <the-mother id="mom3"><slot>God again</slot></the-mother><hr>
#mom4 <the-mother id="mom4"><slot></slot></the-mother><hr>

<script>
  function whoDecides(selector){
    let parent = document.querySelector(selector);
    while (parent.tagName !== "THE-SON")
      parent = parent.shadowRoot.children[0];
    const sonSlot = parent.shadowRoot.children[0].children[0];
    const assigned = sonSlot.assignedNodes({flatten: true});
    console.log(selector, assigned[0]);
  } 
  whoDecides("#son");
  whoDecides("#son2");
  whoDecides("#son3");
  whoDecides("#son4");  
  whoDecides("#pap");
  whoDecides("#pap2");
  whoDecides("#pap3");
  whoDecides("#pap4");
  whoDecides("#mom");
  whoDecides("#mom2");
  whoDecides("#mom3");
  whoDecides("#mom4");
</script> 

What is the expected behavior?
slot in son of #mom2 .assignedNodes({flatten: true}) should return []

What went wrong?
slot in son of #mom2 .assignedNodes({flatten: true}) did return []

Did this work before? N/A 

Does this work in other browsers? No
 Firefox with web comps enabled returns undefined in even more situations.

Chrome version: 70.0.3538.16  Channel: n/a
OS Version: 
Flash Version: 

The template of this test tries to illustrate the decision hierarchy in a family (of slots).

#mom2 problem: If you wrap a custom element inside another custom element, and you want to use the inner elements fallback content within it, how do you accomplish that? The mom does not want to replace the empty slot fallback value of the son with her own. #pap2 does that.

Chrome .assignedNodes({flatten: true}) returns undefined for #mom2 in Chrome.
Firefox .assignedNodes({flatten: true}) returns undefined for #son3,4 #pap3,4, #mom2,3,4.
Also. It would be good if the .assignedNodes({flatten: true}) would replace the slot nodes with its .childNodes instead. It would unify the resolution of both normally slotted DOM nodes, and the fallback DOM nodes. This would be more inline with what (I as) a developer would anticipate.

Today, the standard reads:
----------------------------------
To find flattened slotables for a given slot slot, run these steps:

1. Let result be an empty list.

2. If slot’s root is not a shadow root, then return result.

3. Let slotables be the result of finding slotables given slot.

4. If slotables is the empty list, then append each slotable child of slot, in tree order, to slotables.

5. For each node in slotables:

5. 1. If node is a slot whose root is a shadow root, then:

5. 1. 1. Let temporaryResult be the result of finding flattened slotables given node.

5. 1. 2. Append each slotable in temporaryResult, in order, to result.

5. 2. Otherwise, append node to result.

6. Return result.
----------------------------------

What if the rule instead was?
----------------------------------
1. Let result be an empty list.

2. Let slotables be the result of finding slotables given slot.

3. For each node in slotables:

3. 1. If node is a slot, then:

3. 1. 1. Let temporaryResult be the result of finding flattened slotables given node.

3. 1. 2. Append each slotable in temporaryResult, in order, to result.

4. If slotables is the empty list, then append each slotable child of slot, in tree order, to slotables.

5. Return result.
----------------------------------

This would more or less accomplish the same result, but it would fix the problem with #mom2? And it would unify the treatment of slotted nodes and fallbcak childNodes?

A problem: If you add an empty slot that has nothing assigned to it, then that slot will hide the fallback content in the previous setup. But this feature is a little bit magic know-how. And default slot content could still be hidden using just a whitespace in the tag.
 
Error in bug report. Sorry..
 * "slot of son in mom2".assignedNodes({flatten: true}) does not return undefined, but an empty list. As is correct against spec. 
 * Firefox returns an empty list for #son3,4 #pap3,4, #mom2,3,4  

However, the main problem in how to make enable the-mother element to fallback to the the-son elements' still remains.

Comment 2 by d...@fb.com, Sep 27

It's a bit hard to tell from this what are compatibility bugs and what are spec changes you're proposing here.

Perhaps you could attach a repro for just one case which has different behavior in FF as a HTML page? And explain what the behavior should be per the spec.
Labels: Needs-Triage-M70
Ok, I tried to look more in depth at the problem. It seems to be a spec issue, and both Safari and Chrome follows the spec for assignedNodes({flatten:true}) afaik. 

And the problem also concerns not only the API assignedNodes({flatten:true}), but also how slot elements are resolved when the browser flattens the DOM. 
Here, both Chrome, Safari and FF with web comps enabled follow the spec afaik. 


## The gentle mom spec issue
The #mom2 problem above illustrates the problem best:

1. You create a custom element with a slot, with slot childNodes as default fallback content (the son custom element).

2. You use this custom element in the shadowRoot of another custom element (the mom custom element). The mom custom element should be used by other custom elements/main document.

3. When you make the mom element, you want to:
a. let the author decide slot content first, and
b. if you don't have a particular opinion about a child elements slot content, you want to let the child element slots fallback to their own default content.

4. But how do you accomplish that? 


The minimal problem as an HTML page:
https://codepen.io/orstavik/pen/LJwqRx

## Why "gentle mom" is important
When you make a custom element, that relies on other custom elements, you should follow the "gentle mom" principle described in point 3 above.
You should enable the author who uses your element to set slot values below if they might need to. What the author says should win, always.
But, when you make a custom element "in the middle", you should also avoid setting the fallback content of children slot elements if you don't specifically need to.


A more in-depth description of the problem is here:
https://codepen.io/orstavik/pen/YOmLjG
Cc: viswa.karala@chromium.org
Labels: Triaged-ET Needs-Feedback
Thanks for filing the issue!

@Reporter: If possible could you please provide the screencast of the issue which help in better understanding and further triaging it in better way.

Thanks!
Status: ExternalDependency (was: Unconfirmed)
Marking external dependency since this is not a Chrome issue, but a spec issue. Please file in appropriate spec repos.

Sign in to add a comment