0

I've built a web component and I need to set the body of the component when I construct it.

My web component is:

import {html, PolymerElement} from '@polymer/polymer/polymer-element.js';

class TextBlock extends PolymerElement {
  static get template() {
    var body;
    return html`
      {body}
    `;
  }
}

window.customElements.define('text-block', TextBlock)

The page that contains the component is dynamically generated. What I want to do is insert a text-block element into the page as:

<body>
   <text-block>
       <H1>Title of TextBlock</H1>
  </text-block>
</body>

My problem is that I don't understand how to get the web component to take the content between the text-block start/end tags and return it from the call to template()

Whilst not shown, I'm using a webcomponent as I need to style the text using shadow dom.

Brett Sutton
  • 3,900
  • 2
  • 28
  • 53

1 Answers1

0

Don't use Polymer for new Web Components; Google deprecated it years ago.
See: https://polymer-library.polymer-project.org/
Google can't even keep that page up to date; they renamed Lit-Element/html to just Lit.
See: https://lit.dev
Or its 60+ alternatives: https://webcomponents.dev/blog/all-the-ways-to-make-a-web-component/


You can write Vanilla JavaScript Web Components without the soup-starter Lit

Here is a more extended example to cover your next questions:

<style> /* GLOBAL CSS */
  text-block { /* inheritable styles trickle down into shadowDOM */
    font: 20px Arial;
    color: green;
  }
  div[slot] { /* lightDOM styles are REFLECTED to <slot> in shadowDOM */
    width: 200px;
    border: 2px solid green;
  }
</style>

<text-block prefix="Hello!">
  <!-- lightDOM, hidden when shadowDOM is used, then REFLECTED to <slot> -->
  <div slot="username">Brett</div>
</text-block>

<text-block prefix="Hi,">
  <!-- lightDOM, hidden when shadowDOM is used, then REFLECTED to <slot> -->
  <div slot="username">Danny</div>
</text-block>

<template id="TEXT-BLOCK">
  <style> /* styling shadowDOM */ 
    div { /* styles do NOT style content inside <slot>, as <slot> are REFLECTED content */
      padding: 1em;
      background:gold;
    }
    ::slotted(*) { /* slotted can only style the lightDOM 'skin' */
      background: lightgreen;
    }
  </style>
  <div>
    <slot name="username"></slot>
  </div>
</template>

<script>
  customElements.define('text-block', class extends HTMLElement {
    constructor() {
      // see mum! You can use code *before* super() The documentation is wrong
      let colors = ["blue","red"];
      let template = id => document.getElementById(id).content.cloneNode(true);
      super().attachShadow({mode: 'open'})
             .append(template(this.nodeName)); // get template TEXT-BLOCK
      this.onclick = (evt) => this.style.color = (colors=colors.reverse())[0];
    }
    connectedCallback(){
      this.shadowRoot.querySelector("div").prepend( this.getAttribute("prefix") );
    }
  });
</script>

For (very) long answer on slots see: ::slotted CSS selector for nested children in shadowDOM slot

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49