Lit-element: [question] slotchange event and component lifecycle in Safari.

Created on 15 Mar 2019  路  7Comments  路  Source: Polymer/lit-element

Hi All,
I've a question relating to component lifecycle and listening to slotchange events.
I have created a basic component to describe my findings.

The component has two slots; one default and another named slot called "contents". I have added a slotchange event to both slots as I'm interested to know if the slots have changed.
In both Chrome and Firefox the slotchange events are handled as I expected.

Safari seems to handle the component lifecycle a little differently. Safari handles the slotchange event before the connectedCallback is called.

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Custom Component Test</title>
</head>

<body>
  <script src="./dist/LitElement.js"></script>
  <my-lit-element>
    <div>I'm in the <b>default</b> slot</div>
    <div slot="contents">I'm in the <b>named</b> slot</div>
  </my-lit-element>
</body>
</html>

CustomLitElement.js

import {html, render} from 'lit-html';

class CustomLitElement extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    render(this.template(), this.shadowRoot);
  }

  template() {
    return html`
      <h3>Custom Component using lit-html</h3>
      <div class="default__slot">
        <slot id="default-slot" @slotchange=${this}></slot>
      </div>
      <div class="named__slot">
        <slot id="named-slot" name="contents" @slotchange=${this}></slot>
      </div> `;  
  }

  handleEvent(event) {
    if (event.target.id === 'default-slot') {
      console.log(`slotchange event on default slot`);
    }
    if (event.target.id === 'named-slot') {
      console.log(`slotchange event on named slot`);
    }
  }

  connectedCallback() {
    console.log('connectedCallback - my-lit-element');
  }
}
window.customElements.define('my-lit-element', CustomLitElement);

__Chrome__

  1. connectedCallback - my-lit-element
  2. slotchange event on default slot
  3. slotchange event on named slot

__Firefox__

  1. connectedCallback - my-lit-element
  2. slotchange event on default slot
  3. slotchange event on named slot

__Safari__

  1. slotchange event on default slot
  2. slotchange event on named slot
  3. connectedCallback - my-lit-element

If I move the render function from the constructor to the connectedCallback I will not get the slotchange event, as the mutation (in Safari) happens __before__ the connectedCallback, which is before I've called the render, and registered interest in the slotchange event.

What is the correct order?

Where should I perform the initial render?

Is Safari handling things incorrectly ?

Any help would be appreciated :)

docs More Info Needed

Most helpful comment

This might be a Safari bug. In general if you want to get light DOM children, we've found you need to get an initial set with assignedNodes() as well as listen to slotchange

All 7 comments

This might be a Safari bug. In general if you want to get light DOM children, we've found you need to get an initial set with assignedNodes() as well as listen to slotchange

Actually it is a Safari Bug, https://github.com/whatwg/dom/issues/447

Thanks @justinfagnani, that pointer really helped.
Thanks too, @mzeiher I'll keep an eye on this.

Out of curiosity should I perform the initial render in the constructor or in the connectedCallback?

This might be a Safari bug. In general if you want to get light DOM children, we've found you need to get an initial set with assignedNodes() as well as listen to slotchange

@katejeffreys note to self for docs

Just my humble opinion, but I think Safari got it right and the issue is page load. When the html gets parsed, and before any user interaction or external scripts can be run on that element, how does one know what elements were part of the page and which may have been added later? The answer in Safari is - "you know when connectedCallback fires", but for other browsers, you don't know without a more hack-ish solution.

It sounds like the spec has been updated since this bug was filed, so browsers should be firing slotchange consistently. And the LitElement API has changed as well, so unless anyone feels strongly that there's something to document here, I'm going to mark this as stale.

OK, we don't have "Stale" or "wontfix" labels, so I'm going to label it "More Info Needed." :D

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aadamsx picture aadamsx  路  3Comments

zzzgit picture zzzgit  路  4Comments

YegorUdovchenko picture YegorUdovchenko  路  3Comments

erikkroes picture erikkroes  路  3Comments

ghost picture ghost  路  3Comments