Search code examples
javascriptangulartemplatesangular-materialshadow-dom

Inject templates into html slots


I'm trying to create a custom element that handles tab groups (it's using material under the hood). I need this element to take a dynamic amount of tabs, and I want to do this with html rather than creating a bunch of attributes that need to be filled out. I figured an efficient way of doing this would be to use templates, and then have the custom element determine how many templates were injected and create the appropriate markup and place the contents of the templates appropriately.

The markup would look something like this

  <my-tabgroup>
    <template label="Tab 1">
      <p>Tab 1 content</p>
    </template>
    <template label="Tab 2">
      <p>Tab 2 content</p>
    </template>
    <template label="Tab 3">
      <p>Tab 3 content</p>
    </template>
  </my-tabgroup>

My custom element would look something like this:

<slot #slotContent></slot>

<mat-tab-group>
  <mat-tab *ngFor="let group of groups" [label]="group.label">{{group.content}}</mat-tab>
</mat-tab-group>

(this is not correct code, just giving ideas)
The idea is that the custom element would be able to parse the templates that were passed in the slots and generate the appropriate groups object to dynamically render all the tab groups.

My issue is that I can't seem to access the templates that were passed into the <slot>. Is there a way to access templates that are passed into slots?


Solution

  • Answering my own question here. This came down to a lack of deeper understanding with slots and shadow dom. The light dom (the components that are passed to the slots) actually exist within the custom element but not within the shadow root. The browser does the "virtualization" of placing those light dom elements into the appropriate shadow dom slot.

    I learned that I can use the assignedNodes or assignedElements function on the slot element to get the nodes/elements that would be "put" inside the slot, thus allowing me to evaluate dynamically what's going to be rendered.

    Hope my struggle helps somebody else!