StencilJS - Check for Use of Named Slot

Posted on Oct 9, 2021 (last modified Oct 11, 2021)

Within a Stencil web component, you may sometimes need to determine, with code, whether or not a named slot is being used. I had this need recently, for example, in a layout component that had to render a unique DOM and use unique CSS class names depending on the named slots that were being used. In this post, I'm sharing how to do it.

You need, first of all, to import the Element decorator within the @stencil/core imports as shown below:

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

Now, you can use the Element decorator within your code to gain access to the host element, like this:

@Element() host: HTMLElement;

Declare the slots that you want to check for using private variables:

private panelLeftSlot: HTMLElement; private panelRightSlot: HTMLElement;

Now, in the componentLoad() lifecycle method, you can attempt to populate the representative slot variables. If the user does not inject the named slots when they use your component, the respective variables will simply remain undefined, which you can test for.

componentWillLoad() { this.panelLeftSlot = this.host.querySelector("[slot='panel-left']") this.panelRightSlot = this.host.querySelector("[slot='panel-right']") }

To illustrate this in full, let's look at the code for a component that uses the Bootstrap grid system to render a layout. The DOM structure and CSS classes are to be rendered differently, depending on the given slots.

import { Component, Element, Host, h} from '@stencil/core'; @Component({ tag: 'glass-layout', shadow: false, }) export class GlassLayout { @Element() host: HTMLElement; private panelLeftSlot: HTMLElement; private panelRightSlot: HTMLElement; private panelLeftCSS: string; private panelCenterCSS: string; private panelRightCSS: string; componentWillLoad() { this.panelLeftSlot = this.host.querySelector("[slot='panel-left']") this.panelRightSlot = this.host.querySelector("[slot='panel-right']") if(this.panelLeftSlot && this.panelRightSlot) { this.panelLeftCSS = 'col-md-3' this.panelCenterCSS = 'col-md-6' this.panelRightCSS = 'col-md-3' } else { this.panelLeftCSS = 'col-md-4' this.panelCenterCSS = 'col-md-8' this.panelRightCSS = 'col-md-4' } } render() { return ( <Host> <slot name="header" /> <main class="flex-shrink-0"> <div class="container"> {this.panelLeftSlot || this.panelRightSlot ? <div class="row"> {this.panelLeftSlot ? <div class={this.panelLeftCSS}><slot name="panel-left" /></div> : []} <div class={this.panelCenterCSS}><slot/></div> {this.panelRightSlot ? <div class={this.panelRightCSS}><slot name="panel-right" /></div> : []} </div> : <slot/> } </div> </main> <slot name="footer" /> </Host> ) } }

Now, here's an example that uses all of the named slots available...

<glass-layout> <div slot="header" style="background-color: red">HEADER</div> <!-- START: MAIN CONTENT Main panel is not actually a named slot. Any elements without a named slot will just go in the default, unnamed slot... --> <h1 class="mt-5 display-4">HELLO WORLD!</h1> <p>Paragraph One</p> <p>Paragraph Two</p> <!-- END: MAIN CONTENT --> <div slot="panel-left" style="background-color: purple; height:100%">PANEL LEFT</div> <div slot="panel-right" style="background-color: blue; height:100%">PANEL RIGHT</div> <div slot="footer" style="background-color: green">FOOTER</div> </glass-layout>

Stencil Layout Component - Example 1

Here's an example that uses only the default unnamed slot and the slot named panel-right. Notice the difference in the rendered result that follows.

Stencil Layout Component - Example 2

That's it. I hope I saved you some time. Happy coding!