Re: [w3c/webcomponents] Extensible template parts (#810)

Sorry for the delay in replying to this…

The basic issue is that most components need some way to reliably reference elements (parts) in their shadow tree to manipulate their contents, apply styles, or wire up event handlers.

All of the Elix components have those needs, but since you asked for specific examples, here’s a representative one. The [CalendarMonth](https://component.kitchen/elix/CalendarMonth) component is made up of subelements that render different parts of the calendar: the month/year, the column headers for the week days, and an CalendarDays element that can show the actual grid of dates:

```html
<calendar-month>
  <calendar-month-year-header id=“monthYearHeader"></calendar-month-year-header>
  <calendar-day-names-header id=“dayNamesHeader”></calendar-day-names-header>
  <calendar-days id=“daysGrid”></calendar-days>
</calendar-month>
```

If you set the `date` property on the outer CalendarMonth, one of the things it will do in response is pass that date to the inner CalendarDays date grid. So somewhere in the definition for CalendarMonth there’s code that effectively does:

```js
// The date has changed, pass it to the shadow element showing the grid of dates.
this.daysGrid.date = this.date;
```

The issue lies in the above reference to the subelement, `this.daysGrid`. What’s the best way for a component to create and hold onto such references? There are currently two basic strategies:

1. Always dynamically look up the shadow element in question, e.g., via `this.shadowRoot.getElementById`. This is what we do in Elix. _–or–_
2. Compute a static map/dictionary of the interesting shadow elements after the template has been cloned. It’s my understand that that is what Google’s Polymer library did to create a [node map](https://polymer-library.polymer-project.org/3.0/docs/devguide/dom-template#node-finding), in which `this.$.foo` pointed to a shadow element with ID “foo". This requires a post-clone shadow tree walk via something like `this.shadowRoot.querySelectorAll(‘[id]’)`. I think lit-html does something similar, although instead of using IDs, it appears to maintain a simple array. That array maps one-to-one between the `${...}` template literal placeholders and the shadow nodes produced for those placeholders.

When template instantiation was proposed, the Polymer/lit-html team and I observed it would be useful to provide a `cloneWithParts` template primitive that let someone clone a template and get references to the cloned parts. The developer could imperatively create a list of parts that referenced nodes in a template. (That might entail a tree walk of the template — but the walk is only being done once for the template, not once per component instance.) After invoking `cloneWithParts`, the parts would now reference the nodes in the cloned shadow tree.

Given this, I think the answer to the question about what information would the part need to carry that the browser would clone is: the part would essentially be the `AttributeTemplatePart` or `NodeTemplatePart` from Apple’s proposal — i.e., just the information to effectively address the attribute portion or node, respectively, after the template has been cloned. The main difference from Apple’s proposal is that it’d be possible to construct a set of parts imperatively without requiring, among other things, the use of any particular mustache syntax.

@justinfagnani The above is based on my recollection of the conversation at the April 2019 F2F. If I’ve gotten anything wrong or omitted important details, please chime in.

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

Received on Friday, 13 September 2019 17:29:46 UTC