3

I have a Stencil.JS components:

import {Component, Prop, h} from '@stencil/core';

@Component({
   tag: 'my-comp',
   styleUrl: 'my-comp.css',
   // shadow: true
})

export class MyComp {
   @Prop() active: boolean = false;
   render() {
      return this.active ? <div>
         <slot></slot>
      </div> : null;
   }
}

I expect that content of the slot is not rendering when I use the component in this manner:

<my-comp>
   <p>I'm hidden!</p>
</my-comp>

And, actually it works as expected, when "shadow" set to true in Component decorator. But, when the shadow DOM is disabled, component shows the content of slot regardless of the value of this.active.

I have a feeling that I don't understand how the render works with slots. Could you please explain it to me? I would really appreciate If you know how to work-around this issue without hiding the slot content programatically.

Alex
  • 4,621
  • 1
  • 20
  • 30
  • 1
    Aren't SLOTs only available in ShadowDOM, in lightDOM they are an unknown tag thus display the contents. https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots – Danny '365CSI' Engelman Jun 07 '19 at 09:01
  • @Danny'365CSI'Engelman , looks like you are right. I've overlooked this. Thanks! – Alex Jun 07 '19 at 12:21
  • @Danny'365CSI'Engelman - can you post that as an answer? Might help with searches by others. – G. Tranter Jun 07 '19 at 13:52

2 Answers2

16

The accepted answer is incorrect. Stencil absolutely supports <slot>, even in non-shadow components. That is how content projection works in Stencil.

There are a few caveats; the <slot> elements themselves are not actually rendered by Stencil in lightdom components, they serve only as location markers for where Stencil places children.

Additionally, pursuant to this question, conditionally rendering slots is not supported:
https://github.com/ionic-team/stencil/issues/399

We use <slot> in Stencil lightdom components, and have essentially fallen back on toggling display: none on a wrapper around the <slot> for this purpose. It's not ideal, but it works.

Jon Hieb
  • 760
  • 8
  • 9
  • Hi, for which purpose do you set the wrapper `display: none`? – karthikaruna Jun 09 '22 at 17:15
  • Using `display:none` on the wrapper for the slot didn't work for me, but toggling between `visibility: hidden` and `visibility: visible` works – U. Watt Mar 16 '23 at 08:01
  • @karthikaruna If you need to conditionally render the ``, which is what OP wanted. From the end user's perspective that means that the content should sometimes not be visible. In Stencil lightdom components (those which use `scoped` rather than `shadow`) one of the most ergonomic ways to do this is to conditionally add the `hidden` attribute to the DOM element (or a CSS class) and hide it using CSS. Obviously this is not actually the same as conditional rendering since the children will still mount and lifecycle will run. But the UI will be invisible. In most cases that is sufficient. – Jon Hieb Aug 22 '23 at 20:53
0

See the documentation:
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots

SLOT elements can only be used in shadowDOM, when used in lightDOM (or any DOM) they are unknown tags thus display the contents

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
  • Oh my goodness, this makes so much sense now that you say it that way. I could not figure out what was going on. Thank you. – Marty Penner Nov 07 '19 at 16:10