Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to add <slot>-like elements to a <template> without using Shadow DOM?

Trying to adhere to the DRY principal, I wanted to create a custom component based on a <template>. The code looked something like this (please forgive the corner-cutting as I'm typing this on a phone after an all-nighter):

// base.html

<template id="player">
  <div class="card">
    <div class="card-body">
      <slot name="user-username"></slot>
    </div>
  </div>
</template>

// app.js

class PlayerCard extends HTMLElement {  
  constructor(){
    super();
    let tmpl = querySelector...;
    this.appendChild(tmpl.content.cloneNode();
  }
}

define('player-card', PlayerCard);

// index.html

{% for user in users %}
  <player-card>
    <div slot="user-username">{{ user }}</div>
  </player-card>
{% end for %}

But after smashed dreams and long hours of research, I learned that slots can only be used in Shadow DOMs. The problem with using SDOM is that the internal styling is protected and can't be directly influenced by the external CSS.

This means that, at one hand, i can't inject the data to the template instance, nor can I use Shadow DOM without having to reimplement Bootstrap.

And I'm stuck. To my brain, there must be a way to make this work but my brain is unable to find it — either because it's too complex, or it's too trivial and easy.

Any suggestions please?

like image 238
ahmed Avatar asked Oct 29 '25 03:10

ahmed


1 Answers

Yes, <SLOT>s can only be used inside shadowDOM

But you can do a lot more with styling slots.

For long answer see: ::slotted CSS selector for nested children in shadowDOM slot

customElements.define('player-card', class extends HTMLElement {
    constructor() {
      let template = (id) => document.getElementById(id).content.cloneNode(true);
      super()
         .attachShadow({mode: 'open'})
         .append(template(this.nodeName));
      this.onclick = (evt) => this.style.color='blue';
    }
});
/* GLOBAL CSS */
player-card { /* inheritable styles trickle down into shadowDOM */
  font: 20px Arial;
  color: green;
}
[slot="username"] { /* lightDOM styles are REFLECTED to SLOTs */
  width: 200px;
  border: 2px solid green;
}
<template id="PLAYER-CARD">
  <style shadowDOM-CSS > 
    div { /* styles do not style content in SLOTs */
      padding: 1em;
      background:gold;
    }
    ::slotted(*) { /* slotted can only style the lightDOM 'skin' */
      background: lightgreen;
    }
  </style>
  <div>
    <slot name="username"></slot>
  </div>
</template>

<player-card>
    <!-- lightDOM, hidden when shadowDOM is used, then REFLECTED to SLOT -->
    <div slot="username">Ahmed</div>
</player-card>

<player-card>
    <!-- lightDOM, hidden when shadowDOM is used, then REFLECTED to SLOT -->
    <div slot="username">Danny</div>
</player-card>
like image 191
Danny '365CSI' Engelman Avatar answered Oct 30 '25 18:10

Danny '365CSI' Engelman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!