Open acarlstein opened 3 years ago
This was previously discussed in https://github.com/WICG/webcomponents/issues/66.
@rniwa , the discussion on #66 is about navigate to a fragment inside a shadow tree. This is not my case. My case is a pure CSS trick that doesn't work inside the Web Component when it should.
For example, by clicking a link, I could change the color of a header: Before: After:
Here is the code:
<style>
#message:target { color: red; }
</style>
<body>
<a href="#message">Make the message red</a>
<h2 id="message">Message in a bottle</h2>
</body>
Another example, I could create a toolbar in which the function selection remains active:
However, since target
isn't part of the root of shadow-root, this feature isn't available.
This pure CSS trick doesn't work inside the Web Component.
It's not a pure CSS trick, you are literally navigating to a fragment and that fragment's corresponding ID cannot be found as its inside a shadow tree.
Solving this would need something like delegatesIds = [ list of IDs ]
.
It's not a pure CSS trick, you are literally navigating to a fragment and that fragment's corresponding ID cannot be found as its inside a shadow tree.
@annevk , I called it "trick" to make it easy to understand; however, the fact is that the code below works fine outside the Web Component:
<style>
#message:target {
color: red;
}
</style>
<div>
<a href="#message">Make the message red</a>
<h2 id="message">Message in a bottle</h2>
</div>
The header changes colors when the link is click due :target
.
However, when moved this code into a component itself it fails to do so.
It works fine until its move into a Web Component fails because the target
isn't there in the shadow-root.
I understand that Web Components should be encapsulated and outside links shouldn't be allowed to navigate to the fragment; however, the selector :target
shouldn't be affected.
This piece of the CSS code, #message:target
is affected.
So, at least there should be an alternative than having to write extra JS code to obtain the same effect.
@rniwa , the discussion on #66 is about navigate to a fragment inside a shadow tree. This is not my case. My case is a pure CSS trick that doesn't work inside the Web Component when it should.
No, you're misunderstanding the cause of the problem. The fragment navigation is precisely what's missing & what's causing :target
to never apply inside a shadow tree.
Please go read the definition of :target
before leaving any new comments.
@rniwa , the discussion on #66 is about navigate to a fragment inside a shadow tree. This is not my case. My case is a pure CSS trick that doesn't work inside the Web Component when it should.
No, you're misunderstanding the cause of the problem. The fragment navigation is precisely what's missing & what's causing
:target
to never apply inside a shadow tree.Please go read the definition of
:target
before leaving any new comments.
Thank you. That's is what I'm trying to say which means there is a bug because that piece is missing. If you search for the documentation on the CSS pseudo-class, there is nothing that says "It doesn't work in Web Components by the way"
So my point is, if there is a decision to not include a fragment navigation, at least put something in place so the code I shared doesn't break.
That's is what I'm trying to say which means there is a bug because that piece is missing. If you search for the documentation on the CSS pseudo-class, there is nothing that says "It doesn't work in Web Components by the way"
I don't think this is a bug per se. It's more of a missing feature. This is very much the intended behavior. In general, id references work within each tree, not across shadow boundaries. For example, document.getElementsById(id)
will only find elements with the specified id in the document tree, not any of the shadow trees connected to it.
Solving this would need something like delegatesIds = [ list of IDs ].
The downside of something like this is that the parent tree might not be aware of all ids being exposed via all shadow roots, this would make it easy to potentially have conflicting ids.
An alternative would be to just allow associating an id to a given shadow ::part
e.g.:
<style>
/* Ideally works, although using it .querySelector wouldn't select anything
as it's in a shadow root, so this should arguably be a pseudo-element */
:target {
color: red;
}
</style>
<a href="#myId">Works</a>
<my-element partids="myId:myPart">
<template shadowroot="closed">
<div part="myPart">Foo bar!</div>
<div part="fooPart">Bazz</div>
</template>
</my-element>
The one problem with parts though is that many elements can have the same part name, although this might not be a big deal as we can already have multiple elements with the same id attribute, if we were being consistent with that we'd just ignore all but the first.
Alternatively again this could even be a part of the url similar to scroll-to-text-fragment, e.g. <a href="#myId:~:part=myPart">
, although this would be trickier with CSS (maybe?).
FWIW, for this kind of API, it's very important that there is an opt-in from both component author & user. We can't pollute the global or outer tree's fragment ID from within shadow trees or let users of a component make random parts of a component addressable via a fragment ID in order to maintain the encapsulation we have at shadow boundaries.
Feels like if anything the host should have to map the exported id back to another name.
<c-e importnodes="foo as bar">
<template shadowroot="open">
<div id="foo" exportnode></div>
</template>
</c-e>
That's is what I'm trying to say which means there is a bug because that piece is missing. If you search for the documentation on the CSS pseudo-class, there is nothing that says "It doesn't work in Web Components by the way"
I don't think this is a bug per se. It's more of a missing feature. This is very much the intended behavior. In general, id references work within each tree, not across shadow boundaries. For example,
document.getElementsById(id)
will only find elements with the specified id in the document tree, not any of the shadow trees connected to it.
I will present it in a different way...
There no need to cross boundaries.
You use the example document.getElementById(id)
, did you? Then, how about this.shadowRoot.getElementById(id)
?
Make the :target
work inside the shadow boundaries by itself, as a separate :target
.
I should be able to copy any HTML and CSS code and have it run inside the shadow without surprises. If there is something that shouldn't cross boundaries, then have two, one for document and one for shadow, but both doing what the documentation says it does.
Make the :target work inside the shadow boundaries by itself, as a separate :target.
I don't think this is possible because it's a breaking change, but I agree with your sentiment:
I should be able to copy any HTML and CSS code and have it run inside the shadow without surprises.
Like @rniwa said earlier, it's less a bug and more a missing feature that would probably need to be implemented as a new selector, e.g. :local-target
or :host-target
.
WCCG had their spring F2F in which this was discussed. You can read the full notes of the discussion (https://github.com/WICG/webcomponents/issues/978#issuecomment-1516897276) in which this was discussed, heading entitled "ARIA Mixin & Cross Root ARIA" - where this issue was specifically discussed.
In the meeting, present members of WCCG reached a consensus to discuss further in breakout sessions. I'd like to call out that https://github.com/WICG/webcomponents/issues/1005 is the tracking issue for that breakout, in which this will likely be discussed.
Example
Let's assume you have this Web Component:
Problem
This code will fail because the event
:target
is missing in the root of the shadow.Also, since it isn't in the specifications, there are not signs that other browsers will fix this issue.
Expectations
I was expecting to see the header turn to red when clicking on the link. This works outside the web component but fails to do so inside the web component.