ionic-team / stencil

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
https://stenciljs.com
Other
12.58k stars 788 forks source link

bug: Slotted Content Being Erroneously Hidden When Nested #6029

Open dgibson666 opened 1 month ago

dgibson666 commented 1 month ago

Prerequisites

Stencil Version

4.22.1

Current Behavior

My understanding is that Stencil will place a hidden attribute on a node if it references a named slot that doesn't exist. I know there have been issues around this in the past, so I upgraded Stencil to the very latest and am testing/reporting on v4.22.1. And I am fairly certain you have a bug/regression here.

In my case, I have a component whose render lifecycle method renders a named slot within another component. My slotted content is rendering as hidden. I believe that this check is flagging the named slot as not existing inside of the nested/rendered component rather than the component in which the named slot is defined and belongs. When I updated my component to not render other components, just plain HTML, this issue went away.

I threw a console.log in to be sure the node did not have the hidden attribute on it prior to the render lifecycle hook and it was confirmed.

I am fairly certain that I've composed components that render other components in the past (with optional named slots) without running into this issue.

Expected Behavior

Do not add hidden to the slotted node.

System Info

System: node 18.18.2
    Platform: windows (10.0.22631)
   CPU Model: 13th Gen Intel(R) Core(TM) i7-13700F (24 cpus) 
    Compiler: C:\websites\_sandbox\cbp-design-system\node_modules\@stencil\core\compiler\stencil.js
       Build: 1728498324
     Stencil: 4.22.1
  TypeScript: 5.5.4
      Rollup: 2.56.3
      Parse5: 7.1.2
      jQuery: 4.0.0-pre
      Terser: 5.31.1

Steps to Reproduce

Case 1 (Original code, rendering slotted content as hidden):

  render() {
    console.log(this.host.querySelector('[slot=cbp-accordion-item-label]'));

    return (
      <Host>
        <cbp-flex
          class="cbp-accordion-item--control"
          align-items="center"
          onClick={() => this.handleClick()}
        >
        <slot name="cbp-accordion-item-label" />
          <cbp-flex-item>
            <cbp-button
              type="button"
              class="cbp-accordion-item--toggle"
              fill="ghost"
              color="secondary"
              controls={`${this.headingId}-content`}
              expanded={this.open}
              accessibilityText="Toggle Accordion Item"
              aria-describedby={this.headingId}
              ref={el => (this.control = el)}
            >
              <cbp-icon name="chevron-right"></cbp-icon>
            </cbp-button>
          </cbp-flex-item>

          <cbp-flex-item id={this.headingId} flex-grow="1">
            <slot name="cbp-accordion-item-label" />
            {this.label && <cbp-typography tag={this.headingLevel} variant="heading-sm">{this.label}</cbp-typography>}
          </cbp-flex-item>
        </cbp-flex>
      </Host>
    );
  }

Case 2 (rendering correctly):

  render() {
    console.log(this.host.querySelector('[slot=cbp-accordion-item-label]'));

    return (
      <Host>
        <div 
          class="cbp-accordion-item--control"
          onClick={() => this.handleClick()}
        >
          <cbp-button
            type="button"
            class="cbp-accordion-item--toggle"
            fill="ghost"
            color="secondary"
            controls={`${this.headingId}-content`}
            expanded={this.open}
            accessibilityText="Toggle Accordion Item"
            aria-describedby={this.headingId}
            ref={el => (this.control = el)}
          >
            <cbp-icon name="chevron-right"></cbp-icon>
          </cbp-button>

          <div id={this.headingId} class="cbp-accordion-item--heading">
            <slot name="cbp-accordion-item-label" />
            {this.label && <cbp-typography tag={this.headingLevel} variant="heading-sm">{this.label}</cbp-typography>}
          </div>
        </div>

        <div id={`${this.headingId}-content`} class="cbp-accordion-item--content">
          <slot />
        </div>
      </Host>
    );
  }

Code Reproduction URL

none yet

Additional Information

No response

ionitron-bot[bot] commented 1 month ago

Thanks for the issue! This issue has been labeled as needs reproduction. This label is added to issues that need a code reproduction.

Please reproduce this issue in an Stencil starter component library and provide a way for us to access it (GitHub repo, StackBlitz, etc). Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.

If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was not enough for our team to reproduce the issue.

For a guide on how to create a good reproduction, see our Contributing Guide.

christian-bromann commented 2 weeks ago

@dgibson666 any updates on the reproduction case?