monokh
monokh

Reputation: 1990

Web component template filling multiple named slots

Given the following html template:

<div class="Page">
    Hello <slot name="personName"></slot>. Your name is <slot name="personName"></slot>.
</div>

How is it possible (if at all) to fill both slots with one value using custom elements?

The below demo code will produce:

Hello Bob, Your name is .

Is this intended? Is this the wrong way of displaying a single value in multiple locations of a template?

let tmpl = document.createElement("template");
tmpl.innerHTML = `
  <div>
    Hello <slot name="personName"></slot>. Your name is <slot name="personName"></slot>.
  </div>
`;

class MyElement extends HTMLElement {
  constructor() {
    super();
    let shadowRoot = this.attachShadow({ mode: "open" });
    shadowRoot.appendChild(tmpl.content.cloneNode(true));
  }
}

customElements.define("x-myelement", MyElement);
<x-myelement>
  <span slot="personName">Bob</span>
</x-myelement>

Upvotes: 1

Views: 2720

Answers (2)

Supersharp
Supersharp

Reputation: 31171

It's the normal behavior.

If you want to reuse a variable multiple times, a good solution is to use template literals with placeholders.

In a template literal string (that is a string delimited with back-ticks), placeholders are replaced by the value of the matching variable.

let name = "Bob"
let template = `Hello ${name}. Your name is ${name}`
// template will contain "Hello Bob. Your name is Bob"

You can get the content of the light DOM using querySelector() on the slot attribute, or on any other attribute you prefer. To get the value, use property textContent, innerHTML, or even outerHTML if you wan to keep the surrounding <span> element.

class MyElement extends HTMLElement {
    connectedCallback() {
        var person_name = this.querySelector( '[slot=personName]' ).outerHTML
        this.attachShadow({ mode: "open" })
            .innerHTML = `Hello ${person_name}. Your name is ${person_name}`
    }
}

customElements.define("x-myelement", MyElement)
<x-myelement>
    <span slot="personName">Bob</span>
</x-myelement>

Upvotes: 2

user2946560
user2946560

Reputation: 11

take a look at LitHtml and MDN

make name as an attribute of element, then inject it into the template.

const tmpl = document.createElement('template');
tmpl.innerHTML = `
<style>span{font-weight:bold}</style>
<p>Hello <span id="name"></span> Your name is <span id="name2"></span></p>`;
class MyElement extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({ mode: "open" });
    shadow.appendChild(tmpl.content.cloneNode(true));

    const name = this.getAttribute('personName');
    shadow.querySelector('#name').innerText = name;
    shadow.querySelector('#name2').innerText = name;
  }
}
customElements.define("x-myelement", MyElement);
<x-myelement personName="Bob"></x-myelement>

slots are not supported by all browser, especially named slots.

second, slotted content are not within the scope of the component (shadow dom), unless that was what you where going for?

Upvotes: 0

Related Questions