Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dom-parts] HTMLTemplateElement.fromStrings() API #1019

Open
justinfagnani opened this issue Jul 16, 2023 · 3 comments
Open

[dom-parts] HTMLTemplateElement.fromStrings() API #1019

justinfagnani opened this issue Jul 16, 2023 · 3 comments

Comments

@justinfagnani
Copy link
Contributor

justinfagnani commented Jul 16, 2023

This is an API for template instantiation / DOM Parts suggested recently by Google's security team (edit: by @engelsdamien specifically) that caught my eye.

Essentially it's a imperative way to create a template and a list of parts from template strings, but without having to specify a syntax for expressions.

fromStrings() would be a static method that takes an array of strings (security wants this to be a TemplateStrings array to be unforgeable developer-controlled value) and create DOM parts between each string.

class HTMLTemplateElement {
  static fromStrings(strings: TemplateStringsArray): HTMLTemplateElement;
}

A template system can be built with this quite easily:

const templateCache = new Map();
const html = (strings, ...values) => {
  let template = templateCache.get(strings);
  if (template === undefined) {
    template = HTMLTemplateElement.fromStrings(strings);
    templateCache.set(strings, template);
  }
  return {
    template,
    values,
  };
}

function render(templateResult, node) {
  // clones the template, sets the part values, etc, using:
  // templateResult.template.content.getPartRoot().clone()
}


// Example usage
function renderName(firstName, lastName, about) {
  render(html`<x-foo name="${lastName}, ${firstName}">${about}</x-foo>`);
}

Where template strings are allowed to break and what type of parts those break create would have to be figured out, which is the same for a syntax. It could be that the syntax is the easier piece of the puzzle once that is done, but if syntax were a roadblock, this approach could side-step it for a bit.

@EisenbergEffect
Copy link

My first impressions of this are positive. It's an interesting way to sidestep the syntax question and still potentially get a lot from the platform.

@rictic
Copy link
Contributor

rictic commented Jul 17, 2023

I needed almost this exact API to add DOM Parts support to our template system workbench: rictic/web-template-workbench#1

As part of writing up a polyfill, I had to make some choices around representing bindings inside an element tag. Code like:

html`<div ${x}></div>`

The user intent here is clearly for a NodePart. The template system needs a reference to the <div> and will do something to it involving x.

But for code like:

html`<img src="https://example.com/${name}.png?size=${size}px">`

We need to communicate that we've got bindings into the src attribute interspersed with constant parts. I represented this with metadata on a node part, with a format similar to a TemplateStringsArray:

<?node-part attr src "https://example.com/" ".png?size=" "px" ?>

This worked well. Though looking forward towards template instantiation, I think we will want an actual AttributePart and the attribute value setter from Ryosuke's proposal, or something filling the same role, to coordinate multiple AttributeParts, and static strings, without performing multiple writes to the attribute each time the template is updated.

@rictic
Copy link
Contributor

rictic commented Jul 17, 2023

Another thing that came up: this could use an option to parse the template in an <svg> context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants