salesforce/lwc

A synthetic shadow component can observe that its slot container is native shadow

Opened this issue · 0 comments

Description

The current design of shadow DOM mixed mode is that shadowSupportMode only applies transitively to children, not to slot contents. However, similar to recent issues with native custom element lifecycle (#4249), it is possible for a synthetic-shadow component to observe that it is slotted into a native-shadow component.

Steps to Reproduce

Consider this structure:

<!-- app.html -->
<template>
  <x-slottable>
    <x-slottee></x-slottee>
  </x-slottable>
</template>
<!-- slottable.html -->
<template>
  <template lwc:if={shown}>
    <slot></slot>
  </template>
</template>

If shown is false, then LWC will neither create the <x-slottee> element, nor insert it into the DOM tree. (This is how synthetic shadow works, i.e. slots are lazy.) This means that the <x-slottee> will never fire its constructor/connectedCallback/renderedCallback.

However, if we change slottable.js to native shadow:

export default class Slottable extends LightningElement {
  static shadowSupportMode = 'native'
}

... then now the constructor/connectedCallback/renderedCallback callbacks for <x-slottee> will fire.

One example where this could break is if shown is some boolean that is never expected to be true (e.g. experimentalFeatureWeNeverEnabled), and <x-slottee> is some experimental, broken component that throws an Error in one of its callbacks. As soon as the slottable is migrated from synthetic to native shadow, this will trigger <x-slottee>'s lifecycle hooks to fire, which can cause a breakage.

Both examples use synthetic custom element lifecycle, but this applies with native lifecycle as well.

This could also apply to other cases where there are subtle timing differences between native shadow and synthetic shadow, but the lwc:if example is the simplest I can think of.

Possible Solution

Similarly to the RFC for native lifecycle mixed mode, perhaps shadow DOM mixed mode should also force the entire DOM tree into native shadow mode, including slotted content.