Webcomponents: Allow customizing base URL of a shadow root

Created on 4 Oct 2016  路  23Comments  路  Source: WICG/webcomponents

It'd be very convenient in a number of applications to be able to customize base in shadow root, either via <base> tag or baseURI property. Shadow root are now used for embeds (e.g. Twitter embed) and it'd be good to have relative URL resolution scoped to shadow root.

needs implementer interest shadow-dom

Most helpful comment

Maybe baseURI could be an option to attachShadow and a readonly IDL attribute on ShadowRoot?

All 23 comments

@hayatoito @annevk @domenic

I can see that making a base element inside a shadow tree adjusting the base URI of everything inside the shadow tree, or exposing baseURI IDL attribute on ShadowRoot would be useful in some cases.

Yeah, we should allow <base> in a shadow tree. +1 for that.

As per the current spec, <base> is banned in a shadow tree.
http://w3c.github.io/webcomponents/spec/shadow/#inertness-of-html-elements-in-a-shadow-tree

However, as far as I know, the reason is simply that we do not have bandwidth to support this as a v1 feature.

Let's support this in v2 feature. We might want to update HTML Standard directly: https://html.spec.whatwg.org/#the-base-element

We discussed this before and could not come up with a satisfactory design back then: https://www.w3.org/Bugs/Public/show_bug.cgi?id=20976#c23. (Note that if we go down this route anyway, if we overcome those obstacles somehow, we shouldn't repurpose the base element. We need something static that cannot change.)

Note also that the use case discussed in OP is something that probably warrants the sometimes-discussed isolated shadow trees. Those would have their own base URL due to being isolated.

Maybe baseURI could be an option to attachShadow and a readonly IDL attribute on ShadowRoot?

Maybe, but see the bug I pointed to. It doesn't help when creating elements dynamically.

One way to mitigate that might be adding createElement on ShadowRoot so that base URI, etc... could be appropriately adjusted at the construction time.

Meaning element constructors are broken-by-design?

@annevk : This is why I wanted to make Document as the first mandatory argument for custom elements. That provides a way of scoped custom element registry, etc...

But really, there is no way to know whether a given element is created for a shadow tree or not without giving some information about it. Also, constructor shouldn't be doing something different based to which tree it belongs. e.g. img element only fetches its resource when src attribute is set. Anyhow, all these elements that do work before getting inserted into some tree is really an anti-pattern.

Is there any adoption phase that's executed when an element is appended into shadow root? Can the affected values be efficiently recalculated? E.g. it could look like a smaller-scope update when the document's <base> is changed.

Appending is too late for <img>. @rniwa, that discounts that script might want to perform preloading and such too.

@annevk : I don't think implicitly preloading scripts while it's not connected to a document is a good pattern because that can easily lead to unintentional / accidental fetches users of the elements didn't intend. It's much better to manually Fetch or do it when the element is inserted into a document. For example, link element supports preload attribute but it doesn't start preloading immediately when the attribute is added; it needs to be inserted into a document.

Fair, but as long as the script still has to compute URLs itself, the benefit of this seems marginal, especially as it breaks common patterns. You really want isolation so the script has its own URL.

Fair, but as long as the script still has to compute URLs itself, the benefit of this seems marginal, especially as it breaks common patterns.

What common patterns? Creating an element and expecting it to load before it gets connected to a document isn't really a common pattern these days. I'm not aware of any JS frameworks or libraries that do anything remotely close to that.

And they don't load resources outside of that? Seems implausible.

Some apps do load resources outside of their components but that's not gonna change just because they use shadow DOM or custom elements. Things like GraphQL isn't going to make disconnected component start fetching stuff, and that's by design. So I'm not at all convinced that prefecthing resources inside components disconnected from a document is something developers want.

When loading a resource outside of DOM, the script has all necessary tools to construct the right URL already - this is correct. And it's certainly a valid use case. I don't think any additional help is needed for this.

On the other hand, where help could be useful is specifically in declarative DOM that's imported into a shadow root. Without a way to affect this, we are left to rewrite src and href attributes in images, links, etc - this is error prone and impacts performance negatively.

Here's how I look at it from purely API standpoint. Suppose I have a detached DOM, e.g. loading via XHR or constructed as document.implementation.createHTMLDocument('') with content:

<html>
<head>
<base href="http://foo.com">
</head>
<body>
  <div id="root">
    <img src="/logo.png">
    <a href="/contact">Contact</a>
  </div>

At this point:

doc.querySelector('a').href == 'http://foo.com/contact'

Next, I import most of this DOM into shadow root on a bar.com page, for instance like this:

var root = doc.getElementById('root');
var importedRoot = document.importNode(root, true);

Now:

importedRoot.querySelector('a').href == 'http://bar.com/contact'

It seems somewhat illogical from API point of view that I'd now have to rewrite anchors and images to still point to foo.com even though all the information is there. I realize that this is pretty arguable what should actually happen. But it also seems that there should be an easy way to preserve the base when importing a fragment of a DOM.

So, perhaps, supporting a base in shadow root is not the right answer, but the same can be enabled in other APIs, e.g. via importNode?

@dvoytenko I think that's a reasonable suggestion. It will require quite a bit of work to make base URL a concept (potentially) bound to elements again and figure out all the edge cases, but in principle that seems doable if the current situation is indeed big enough of a hassle.

A related question is whether this is a problem just for base URLs, or whether we also need to do this for language and similar such things.

URL is the only one I can think off at this time.

We're closing this. We're only interested in solving this as part of another feature, such as HTML Modules or Custom Element Registries.

@annevk are there references to exploration of this for other features, e.g. CE registries?

Yeah, sorry about that: #645 and #716.

Was this page helpful?
0 / 5 - 0 ratings