Closed Bug 1724680 Opened 2 months ago Closed 2 months ago

slotchange event does not get triggered for child element updates

Categories

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

Firefox 90
defect

Tracking

()

RESOLVED INVALID

People

(Reporter: Kokujou, Unassigned)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0

Steps to reproduce:

i have a webcomponent using slots like:
<slot name="xyz" @slotChange="${component.requestUpdate(undefined)}"></slot>

now in the implementationPart i have:
<component>
<div slot="xyz" ?hidden="${text("text knob").length<=0}">${text("text knob")}</div>
</component>

Actual results:

if you don't know storybooks, this code will generate a so called knob, which is an input field live-updating the assigned properties.
but sadly whatever i do the slotchange event is just triggered when the element is assigned, but no matter how many changes i do.

Expected results:

the slot change event should trigger whenever the text or the hidden property is updated

The Bugbug bot thinks this bug should belong to the 'Core::DOM: Events' component, and is moving the bug to that component. Please revert this change in case you think the bot is wrong.

Component: Untriaged → DOM: Events
Product: Firefox → Core

Can you attach an HTML file that reproduces the issue so that we can take a look? Thanks.

Blocks: shadowdom
Component: DOM: Events → DOM: Core & HTML
Flags: needinfo?(Kokujou)

i have no idea to which component this belongs...

and i already provided a minimal code example. it's business code so i can't just put the whole component in a public place.

but it's really simple. i'm using LitHTML for WebComponents.
So create a component like:

export class SomeComponent extends LitElement {
 render(){
  return html`<slot name="abc" @slotChange="${()=>alert('test)}"></slot>` ;
 }
}

and reference it like

<some-component>
 <div slot="abc">test</div>
</some-component>

then you can either take some javascript code or use F12 to modify anything in this component and you will see... nothing.

the slotChange event is just getting fired if you change the slot attribute and i have no other possibility to refresh my component after a slot change.

in my oppinion it should always be possible in an easy way to listen to changes to elements. i don't want to use some strange MutationObserver as a substitute, which, btw. is also not detecting the change.

Flags: needinfo?(Kokujou)
Attached file test-case?

Does it behave as you expect in other browsers? Here browsers seem to behave the same on this test-case... A page that shows the behavior difference across browsers would be great.

Flags: needinfo?(Kokujou)

same problem in chrome. i don't know if it's now a bug for both browsers or if i need to report this somewhere else... if yes please point me to the right direction

the test case works too... which is quite surprising because i thought it would at least detect if there's a new item added to the slot... it seems to be really broken

Flags: needinfo?(Kokujou)

Ok, if it's broken in all browsers it's probably an issue with the standard. You should file an issue in https://github.com/WICG/webcomponents/issues/new explaining your use case and such.

But I'd think that slotchange works that way for a reason. You don't want to impose a perf penalty to all shadow DOM users just because. To observe tree mutations you need MutationObserver (but you need it on the slotted node, not the <slot>).

So I think to achieve what you want you need to use a combination of slotchange and MutationObserver, something like:

slot.addEventListener("slotchange", function() {
  disconnectOldMutationObserver();
  let observer = new MutationObserver(...);
  for (let node of slot.assignedNodes()) {
    observer.observe(node);
  }
})

Or something of that sort.

i think the better way to do it is to assign only one mutation observer to the root.
note that the slotted content of a webcomponent will be displayed outside of the shadow root.
as such it's enough to assign the Mutation Observer in the component itself.
then just call the requestUpdate and everything is fine.

however i never used this mutation observer and i'm a bit worried about created overhead... i i don't want something like "deep compare the dom with the old dom every 100ms"

I don't see any browser issue here. If the spec is changed, a new bug should be filed.

Status: UNCONFIRMED → RESOLVED
Closed: 2 months ago
Resolution: --- → INVALID

You don't want to impose a perf penalty to all shadow DOM users just because

Why do you believe an event API would impose a penalty on all users? That depends on how that event system is implemented.

For one, the event machinery (observation of DOM element(s) by the engine) only needs to be enabled place if and only if an event listener is added. Secondly, it is much easier for developers to defer/batch code off of event listeners than using MutationObserver. Lastly, it would be easy to add an new addEventListener option like {deferred: true} (even make true the default for DOM events).

I don't see any reason why event callbacks need to be a loss of performance. They have a better developer experience than with MutationObserver, and plus they can essentially operate the same way as with MutationObserver when deferred.

Making a MutationObserver API only complicated web developer programs.

Let's get past the mentality that events ruin performance merely because a past implementation was implemented in a non-performant way.

Heck, even add a new {batch: true} option (default to true) to fold multiple of the same event into one. There's ways to achieve performance without creating worse developer experience.

The discussion about adding some new API belongs to whatwg.
If you file a spec issue, could you also link that here, thanks.

You need to log in before you can comment on or make changes to this bug.