Skip to content

bug: Conditional slot rendering removes always the last slot element, using key is a workaround #5263

@michael-jahn-dev

Description

@michael-jahn-dev

Prerequisites

Stencil Version

We were using 4.8.2 but it also happens with 4.10.0

Current Behavior

It occurs that always the last slot element will get removed in shadow dom when conditionally rendering the elements and removing the source slot element in the light dom.

experimentalSlotFixes makes no difference but using the "key" prop with a unique name fixes the issue.

Consider the following basic example below.

Expected Behavior

The Header Slot shall be removed in the example but the Footer Slot should be kept.

System Info

npx stencil info

      System: node 20.10.0
    Platform: darwin (23.2.0)
   CPU Model: Apple M1 Pro (10 cpus)
    Compiler: /Users/michaelworm/projects/porsche-design-system/node_modules/@stencil/core/compiler/stencil.js
       Build: 1702322155
     Stencil: 4.8.2 🐳
  TypeScript: 5.2.2
      Rollup: 2.42.3
      Parse5: 7.1.2
      Sizzle: 2.42.3
      Terser: 5.26.0

Steps to Reproduce

When clicking on "Remove Header" the Footer Slot will get removed and the Header Slot will be empty.

<p-example>
  <div slot="header">
    <h1>Header Slot</h1>
  </div>

  <p>Default Slot for Content</p>
  <button onclick="document.querySelector('[slot=header]').remove()">Remove Header</button>

  <div slot="footer">
    <p>Footer Slot</p>
  </div>
</p-example>
import { Component, Element, forceUpdate, h, type JSX } from '@stencil/core';

@Component({
  tag: 'p-example',
  shadow: true,
})
export class Example {
  @Element() public host!: HTMLElement;

  public render(): JSX.Element {
    const hasHeader = !!this.host.querySelector('[slot="header"]');
    const hasFooter = !!this.host.querySelector('[slot="footer"]');

    return (
      <div>
        {hasHeader && <slot name="header" onSlotchange={() => forceUpdate(this.host)} />}
        <slot />
        {hasFooter && <slot name="footer" onSlotchange={() => forceUpdate(this.host)} />}
      </div>
    );
  }
}

It seems that when adding elements between the slots, the bug does not occur.

...
<div>
  {hasHeader && <slot name="header" onSlotchange={() => forceUpdate(this.host)} />}
  <div></div>
  <slot />
  <div></div>
  {hasFooter && <slot name="footer" onSlotchange={() => forceUpdate(this.host)} />}
</div>
...

Code Reproduction URL

https://stackblitz.com/edit/node-dhtsl3?file=package.json,src%2Fcomponents%2Fmy-comp.tsx

Additional Information

Remove the "key" props in the StackBlitz Demo to see the issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug: ValidatedThis PR or Issue is verified to be a bug within StencilHas WorkaroundThis PR or Issue has a work around detailed within it.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions