Re: [WICG/webcomponents] HTML Modules: JavaScript Scoping of ShadowDom Children (Issue #959)

Direct import of HTML templates as `DocumentFragment` would be fine for me and my use cases. I do similar for CSS imports. Right now mine are written like this (I've stripped class extensions to a declarative functional style), so here's a real-world example of how it would help me:

````diff
import styles from './Card.css' assert { type: 'css' };
+import template from './Card.html' assert { type: 'html' };
import Container from './Container.js';

export default Container
  .extend()
  .css(styles)
-  .html`
-   <slot id=primary-action name=primary-action></slot>
-   <div id=outline></div>
- `
+ .html(template) 
  .autoRegister('mdw-card');
````

-----------

Perhaps extending `onclick` to export `host` as a parameter could be a tangential solution. Currently, it exposes `this` and `event`. Why not `host` as well? `this` is actually unclear anyway (element, static, or instance?), and I personally try to avoid the reference whenever possible.

````diff
<template id="myCustomElementTemplate">
-  <button id=button><slot></slot></button> // Manually bind in constructor
-  <button on-click="{handleClick}"><slot></slot></button> // Custom attribute requiring interpolation
-  <button onclick="this.getRootNode().host.handleClick()"><slot></slot></button> // Unintuitive way to auto-bind
+  <button onclick="host.handleClick()"><slot></slot></button> // Clear
</template>

<script type="module">
    /* ... */
    class myCustomElement extends HTMLElement {
       static {
         customElements.define('x-button', this);
       }
        constructor() {
            super();
            const shadowRoot = this.attachShadow({ mode: "open" });
            const template = document.getElementById("myCustomElementTemplate");
            shadowRoot.appendChild(template.content.cloneNode(true));
-           // Manual bind
-           shadowRoot.getElementById('button').addEventListener('click', this.handleClick);
-           // Interpolate
-           for (const el of shadowRoot.querySelectorAll('[on-click]')) {
-             el.addEventListener('click', this[
-               /^{(.+)}$/.exec(el.getAttribute('on-click'))[1]
-             ]);
-           }
        }
        handleClick() {
            window.alert('You clicked me!');
        }
    }
    /* ... */
</script>

<x-button>Click me</x-button>
````

This way the browser doesn't really have to parse anything or walk the tree. It just uses the standard `onclick`. Browser implementers can choose to optimize by sharing a single anonymous function as long as the template being cloned is the same. You still don't have the ability to remove the event listener, but I'll be honest, authors can tap into `connectedCallback()` or `constructor()` if they want that level of control. Same with passive events.



-- 
Reply to this email directly or view it on GitHub:
https://github.com/WICG/webcomponents/issues/959#issuecomment-1367416841
You are receiving this because you are subscribed to this thread.

Message ID: <WICG/webcomponents/issues/959/1367416841@github.com>

Received on Thursday, 29 December 2022 15:39:36 UTC