Open Bug 1494609 Opened 6 years ago Updated 2 years ago

assignedNodes({flatten: true}) and flattening assigned nodes in spec does not fallback correctly

Categories

(Core :: DOM: Core & HTML, defect, P3)

62 Branch
defect

Tracking

()

UNCONFIRMED

People

(Reporter: orstavik77, Unassigned)

References

Details

Attachments

(2 files)

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0 Build ID: 20180830143136 Steps to reproduce: https://codepen.io/orstavik/pen/YOmLjG <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 = "DOM engine: <b><slot>son decides</slot></b>"; } } customElements.define("the-mother", TheMother); customElements.define("the-father", TheFather); customElements.define("the-son", TheSon); </script> #son <br><the-son id="son">God decides</the-son><hr> #son2 <br><the-son id="son2"></the-son><hr> #son3 <br><the-son id="son3"><slot>God again</slot></the-son><hr> #son4 <br><the-son id="son4"><slot></slot></the-son><hr> #pap <br><the-father id="pap">God decides</the-father><hr> #pap2 <br><the-father id="pap2"></the-father><hr> #pap3 <br><the-father id="pap3"><slot>God again</slot></the-father><hr> #pap4 <br><the-father id="pap4"><slot></slot></the-father><hr> #mom <br><the-mother id="mom">God decides</the-mother><hr> #mom2 (????)<br><the-mother id="mom2"></the-mother><hr> #mom3 <br><the-mother id="mom3"><slot>God again</slot></the-mother><hr> #mom4 <br><the-mother id="mom4"><slot></slot></the-mother><hr> <script> function assignedNodesFlattenSuggestion(slot){ let res = []; for(let assigned of slot.assignedNodes()){ if (assigned instanceof HTMLSlotElement){ res = res.concat(assignedNodesFlattenSuggestion(assigned)); } else { res.push(assigned); } } if (res.length === 0){ res = Array.from(slot.childNodes); } return res; } function printAssigned(label, ar, parent){ const div = document.createElement("div"); ar = ar.map(n => { if (n instanceof HTMLSlotElement) return "SLOT->[" + Array.from(n.childNodes).map(n2 => n2.textContent).join(", ") + "]"; return n.textContent; }); div.innerText = label + ": [" + ar.join("") + "]"; parent.after(div); } function whoDecides(selector){ let parent = document.querySelector(selector); let root = parent; while (parent.tagName !== "THE-SON") parent = parent.shadowRoot.children[0]; const sonSlot = parent.shadowRoot.children[0].children[0]; printAssigned("suggestion.assignedNodes({flatten: true})", assignedNodesFlattenSuggestion(sonSlot), root); printAssigned("API.assignedNodes({flatten: true})", sonSlot.assignedNodes({flatten: true}), root); } 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> Actual results: When FF flattens the DOM it works the same as both Chrome and Safari and the spec. But HTMLSlotElement.assignedNodes({flatten: true}) returns the wrong result for: #son3, #pap3 and #mom3. Also, #son3, #pap3 and #mom3 and #son4, #pap4 and #mom4 should return a list that contains the Slot element from the main document. The error is that it is an empty array instead of an array with a text node "God again". Expected results: The problem is that the expected result from the spec that one sees in both Chrome and Safari is itself problematic. 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: 3a. let the author decide slot content first, and 3b. 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? For a full discussion of the problem, see attachment or just: https://codepen.io/orstavik/pen/YOmLjG It seems FF behavior for .assignedNodes({flatten: true}) is closer to what the spec should be, than what the spec is.
Thanks for bringing this to our attention. Our plan is to fix the mismatch with the DOM Standard to not allow slot elements to be used outside shadow trees. Pursuing a change in the standard is probably best done through https://github.com/whatwg/html/issues for this particular API, but I suspect it's too late to make such a change. Maybe an alternative API could be added if there's sufficient demand.
Attached file slotFallbackCSS.html
Thank you very much for the quick response! I did a little more research into this. And I found another related problem with Slot childNodes (Slot fallback nodes) and CSS. See the slotFallbackCSS.html attachment or https://codepen.io/orstavik/pen/dgyWMM I'm not 100% sure, but with the current setup for assigning childNodes of slot elements, I think CSS style encapsulation for web components break? Also, so not to cause confusion, the problem with the standard is that it DOES allow the use of slot elements outside of shadowRoot. In fact, slot elements in the main document (outside shadowRoot) persist into the flattened DOM. The joke becoming: "Do you know what an abnormal slot element is? a normal html element." I will try to pursue the problem with whatwg.org directly.
Component: Untriaged → DOM
Priority: -- → P3
Product: Firefox → Core
Component: DOM → DOM: Core & HTML
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: