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

Implementing Document.prototype.createHTML #996

Closed
manngo opened this issue Jun 26, 2021 · 6 comments
Closed

Implementing Document.prototype.createHTML #996

manngo opened this issue Jun 26, 2021 · 6 comments

Comments

@manngo
Copy link

manngo commented Jun 26, 2021

I am new to this particular part of the world. Please let me know whether this is the right place for this suggestion.

I would like to propose an addition to the Document prototype. This is to allow you to create a new element using HTML. This is consistent with other DOM properties and methods, such as innerHTML and insertAdjacentHTML().

To illustrate the concept, I have this polyfill:

Document.prototype.createHTML=html=>{
	let template=document.createElement('template');
	template.insertAdjacentHTML('beforeend',html);
	return template.lastChild;
};

You could then use it as follows:

let img=document.createHTML('<img width="40" height="30" alt="alt text" title="title text">');
document.querySelector('h1').insertAdjacentElement('afterend',img);
img.src='https://resources.whatwg.org/logo.svg';

See the following fiddle: https://jsfiddle.net/internotes/sbxpk15z/1/

To create the img element above using traditional DOM methods requires half a dozen steps. You wouldn’t be able to take a shortcut via insertAdjacentHTML() since that doesn’t generate a separate element which can be accessed after the event, such as when you want to change the image’s src.

In comparison, jQuery has something similar in its multipurpose jQuery() function, but this proposal adds the feature to Vanilla JavaScript.

@bathos
Copy link

bathos commented Jun 26, 2021

I would also appreciate a more direct JS API for "parse a fragment in template context". However, I'd expect it to return a DocumentFragment node, not the last direct child node of the fragment.

(btw I think in your example code you likely meant to write template.content.lastChild rather than template.lastChild.)


Edit re: "btw": I just realized the line before uses insertAdjacentHTML, so the missing ".content" isn't a typo. But using this method doesn't actually do inert template parsing - reactions run, etc. AFAICT you have to use innerHTML to get template mode parsing. (Looks like there's a note about this).

@WebReflection
Copy link

I would argue this is a road to more XSS issues than we have already.

There are many libraries that allows you to create nodes via template literal tags, ensuring XSS safety, better attributes handling, without providing another footgun on the client side API.

import {html, svg} from "uhtml";
let img = html.node`<img />`;

you can also create SVG which looks not part of this proposal.

HTML injections are also going to be flagged as untrusted code, so the least ways we have to inject raw strings as HTML, the better, imho.

@bathos
Copy link

bathos commented Jun 26, 2021

Any such method would be a sink subject to trusted types rules. (It doesn't make a difference if there were a thousand; static analysis of JS can't establish that even one isn't used, hence the need for the runtime TT API. Any security practice that would break if a new sink existed is already not actually working.)

@manngo
Copy link
Author

manngo commented Jun 26, 2021

There are many libraries that allows you to create nodes via template literal tags, ensuring XSS safety, better attributes handling, without providing another footgun on the client side API.

I’m not a fan of importing too many libraries. Given that it is relatively simple to do the same thing with three simple lines of code:

let template=let template=document.createElement('template');
template.insertAdjacentHTML('beforeend','<img width="40" height="30" alt="alt text" title="title text">');
let img=template.lastChild;

I think using a library is overkilling it.

The point is that I can’t see any and new XSS or other issues which haven’t already been addressed for insertAdjacentHTML() or innerHTML.

@WebReflection
Copy link

WebReflection commented Jun 26, 2021

It doesn't make a difference if there were a thousand

Imagine JS had thousand ways to eval code ... and the count is already pretty high ... would you propose a new way to eval ?

@manngo your code could be simpler:

let template=document.createElement('template');
template.innerHTML = '<img width="40" height="30" alt="alt text" title="title text">';
let img=template.content.lastChild;

My point is: as the boilerplate is minimal, but a new method that encourage even more innerHTML in the wild is proposed, are we sure we really want this new method at all?

edit and where is the SVG counterpart ?

@annevk
Copy link
Member

annevk commented Jun 26, 2021

Good to know there's still interest in this general idea. Duplicating this into #150.

@annevk annevk closed this as completed Jun 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants