Skip to content

2023 Cross Shadow_Root_IDREF_associations

Alice edited this page Jun 8, 2023 · 2 revisions

Cross-Shadow Root IDREF associations

Alice: we can discuss the things in the issue. I have been working on this with people since 2014.

Rego: Igalia, I've worked on this a bit last year German: Igalia, interest Oriol: Igalia, CSS working group. I have worked a little Gyuyoung: Work at Igalia Byungwoo: Igalia Emilio: Mozilla, shadowdom, css Julie: Igalia, a11y Shin: Igalia, Chromium Fred: Igalia, a11y Anne: Apple, WK team, Web Components Valerie: Igalia, co-chair ARIA WG Benny Powers, Principal UX engineer at redhat Ben Howell, microsoft, newer to web component but I'm working on implementaiton of semantic delegate for chromium. Brian Kardell, igalia Alex, Ryosuke Niwa, apple, web components in webkit Nolan Lawson, salesforce, we want to solve accessibility problems for web components

Alice: I want to try to spend a little bit of time coming to some shared understanding of what problems we are trying to solve. Before jumping into trying to solve the wrong problem.

SLIDES: https://people.igalia.com/alice/shadow-idrefs/

Alice: (describes slides) "What problem/s are we trying to solve?" these three problems have a lot of overlap.

Alice: First problem examples - "Wrapping semantic elements" slides. Example of "has a" relationship trying to fix a "is a" relationship. The second example is my opinion that is should work, because it is common enough, maybe someone disagrees.

Alice: Second problem example - "Serializing Element-type IDL attributes" slides. third problem example - "Referring into shadow roots" slides

Alice: how well does this describe problems that developers are experiencing right now?

Brian: It describes the open issues on these things very well.

Ben: That covers our usecases in our design system.

Alice: Web components face to face and ARIA face to face discussed this. In the notes I linked to the minutes. They have the usual problem of the minutes which is that is not a great recap for those who could not attend. (see slides for outcome from meeting)

Anne: correction, my idea was that FACE and Semantic delegate could be coupled in some way

Brian: in the scope of problems we try to solve, the ones you are talking about with semantic delegate, and the hisotry of discussion around this go back a ways. Maciej (from Apple) was saying that he didn't like the original design of Shadow DOM because it has limits on many of the same problems: Authors can't create shadow dom on common elements because they already have a shadow dom (that's a limit of the particular choices in design, not inherent). Similarly the is= attribute was also trying to address this to some level, that also was in conflict with other shadow doms and Apple didn't agree to that. It seems there are a bunch of problems that want some behavior of the semantic delegate. Maybe it would be solved if we could come up with a nice pattern for mixins, like for idl, in DOM. That seemed to be the agreement last TPAC. What problems would this help alleviate?

Anne: is that what form associated custom elements are?

Brian: they can't be serialized exactly that way. There is no way to make a form associated custom element as a mix in. if you want some of the behaviors, htis is a regular element but it will borrow some of your IDL meaning. This might be interesting because a couple OS do their accessibility tree in the same way. I think it is IOS that does that. Where you are not limited to super rigid definition of what a thing is, you can mix them together.

anne: even form associated custom elements let you pick and choose what you want to implement.

Alice: back to the minutes, name tree targeting....???

Anne: I think that was about, if you have delegation or relfection, at some point you want multiple inbounds for the same property. So you need some kind of naming to go along with the reference ot disambiguate them. Isn't there something.... ()

Emilio: "export parts"

Alice: We need an element proxy concept.. I think I got that gist of that

Nolan: the only thing that came out of that so far is a comment on the issue, I'll dig it up: https://github.com/WICG/aom/issues/195#issuecomment-1544494836

Nolan: to add extra encapsulation.... we would need some kind of proxy objects, so that you don't actually expose the guts.

Alice: Building nicer bridges on top of ARIA -- does anyone know what that was about?

Anne: once we have the low level primates figured out, maybe we can make better higher level abstractions

Alice: the ARIA f2f was mostly an intro to the topic. Aaron had one suggestion. Different attributes on the shadow host to different elements in the shadow root.

Alice: along similar lines of coming to an understanding again about the shared goals of shadow dom as we design apis against it. See slides.

Alice: I think the ultimate goal is to have resuable, updatable components. Pages don't prevent refactoring because the page breaks when the component changes. Any other ultimate goals or factors that are important?

Anne: no more that can be realized right now, and spectre made harder

Alice: how well is the current implementation of shadow dom... if you are not using closed shadow roots, what is preventing you?

Beny: I want to give a picture of our usage at Red Hat, we only want open shadowroot, no interested in closed shadowroots. Our interest i

s in DOM and CSS encapsulation so that component authors can write their own style/etc, without running into other things. Also we are interested in some performance improvement. Points 4 and 5 on the design goals. If someone sent me a PR with a closed shadowroot, I'd probably send it back.

from the chat room, benny wrote: like nolan, we desire to ship packages with semver and avoid breaking changes. for public apis: host attrs, part names, css props, and public fields/methods suffice. we treat our shadow root contents (excepting part names and css prop names) as private. we do not guarantee the structure of our open shadow roots we do not encourage or support users manipulating open shadow roots, and when we find cases of that, we work with those teams to revert those kinds of 'patches' our biggest blockers at redhat are a11y with face and dsd (waiting on moz)

Anne: can you explain more why you need open? Can you explain why you don't want closed

Benny: we have cases when were need information about the tree. (?)is a useful API. Debugging, programmatic access, automated testing. We never though, "oh if only we had a closed shadow root".

Anne: you never have a problem with users using your components and relying on them

Benny: we have strong conventions, and if things come up, we work with teams to prevent bad hacks

Anne: so this works because you are a closed strong system

Benn: where our design system is federated

Brian: I was going to say I have been working in OpenUI, I haven't found one system that uses closed roots. Adobe isn't, sales force isn't, microsoft isn't, showlace (?) isn't, I looked at the http archive, I couldn't find. Only tracking and ad stuff -- not for shadow root but tracking purposes. That is just some info.

Anne: If you don't use closed shadow root, anyone can get to your component. Anyone can manipulate your internals.

Brian: when we upgrade libraries, it is a manual process. They are unlike native elements, native elements cannot break. There is some willingness to have some breakage. Open shadow root is a speedbump, not a stop -- you should probably not fool around in here.

Nolan: at sales force we use type 1 and type 2 encapsulation. We don't want people to make dependencies on internal implementations. we have strick backwards compatibility issues for our customers. the API does not change for a long time. Type 2... we don't actually use shadow dom, we use a poly fill, we don't use closed shadowdom like provide by browser, we simulated it in a way. It comes from the shadow Realms polyfill. We tightly control the experience of a developer. We have disporate componetns on teh page, from different authors, the authors can only reach into their own component. We are acting like a cop.

Alice: it sounds like you have a friend class, like in c++, you have a concept of limited access.

Nolan: Yeah it is tightly controlled, but it is tightly controlled similar to the browsers, so its somewhat type 2 like.

Alice: do I understand: teh reason you don't use it is because you do want some limited use?

Nolan: The reason we are struggling to used native shadow dom is the accessibility issue. we can't break that for our customers. We can cheat in our polyfill. As for closed shadowroots... we don't use because we have our own mechanism for providing a "sort of" closed shadow dom.

Ryosuke: can we go back to the topic of ARIA?

Alice: What would a proxy get you on top of "Encapsulation-preserving element references"

Nolan: Anne brought this up in the f2f. Any element int his example that wants someone to point externally outside in to it's option, it would need to expose somehow its entire elemen. You just want someone to point at the element, but what you do is give them the entire element.

Alice: can you pass in the element that wants to refer to the element?

Nolan: opposite problem.

Alice: Proxy helps you do this, but without passing around the actual element reference. I like this idea, I don't want to limit to ARIA. Having an element that is like an element that isn't an element, that can be used in the same way as an element... I like the idea, writing the spec sounds like a challenge. Anne, Ryoske?

Benny: my comment is not about element proxy.

Alice: my question is how does could the proxy work in practices

Anne: early on, you mentioned serialization.... which nothing solves. For cross tree references, we gave up, because you would get in out of sync states. It would be even more involved in this case. if we don't need serialization, then you can design a bridging system, where either the custom element internals interface, or shadowroot interface, you can add a mapping for inward and outward references. Some open questions are -- we have 8 aria properites with element references. how many need ot go inward, how many need to go outward, do they all have multiple values... unforutnatley we haven't made a lot of progress on the usecases. I had a question from early on, you said you want to focus on label?

Alice: focus on scenario on wrapping a semantic element outside of the shadow dom

Anne: but you don't like delegates label

Alice: its just a small sliver of the broader problem. if an author is wrapping an element like this, how many different things do you need to set on the shadow root for it work? I think that it should be one

Anne: does the wrapper have meaning though? because the wrapper might add meaning. then you need to combine meanings. So, we need to flesh out how many exact usecases, how many of these are out in the wild?

Benny: From the user perspective, the host is the semantic input element. We were unable to use a native inputs inside the shadow root, because two inputs would be reported to the screen reader, the wrapper element and the internal input. Here is the issue: https://github.com/WICG/webcomponents/issues/1014

Alice: why do you want the host to have the semmantic

Benny: It seems to me that when I was writing the element, the intention of the element internals API, is to reflect the state of the internal input.

Nolan: I was going to respond to anne. Anne was implying was the question of the reference into the shadow root, is it only active-descendent. I have seen this come up for aria-controls, and aria-owns.

Anne: I wasn't trying to ask about that specifically, I want to know for all, we should audit all 8 and understand them. I think I have an issue on leo balters repo.

Alice: back to benny's comment. The just of it for me was that the host is form associated, even tho you have a form inside, only the host can be form associated. Going into the semantic delegate. The idea that you can make an "is a" association. There are cases where this does not suffice. The question is should we do something that doesn't work in all cases. Should you be able to delegate form association as well. Similar ot implicit label association.

Anne: this is my coupling suggestion. You set up your custom element, and you say you are form associated, through this thing.

Alice: this suggests that the power of the semantic delegate type concept might be more than what you could provide with id forwarding or attribute forwarding. you could do "form=", but that would go in the other direction

anne: if form= worked across boundaries, you could do that

Alice: I wanted to touch on the globalid thing, I wanted to put forward -- the reason that I find this somewhat compelling, not good if we go in the direction of capsulation perserving element references, it is a declarative equivalent of that concept. its a way for a shadow root to opt in. maybe it plays into the proxy idea. the idea would be you give it a global id or proxy id, where you can refer to it with some extra syntax. I wanted to make sure we touch on this, its an option for making declarative some of the things that are only imperative.

Anne: if you were writing this component, the global id would have ot be a parameter during construction. if you give out references, sounds scare

alice: depens on what it is used for

Brian: no one should be able to get an element out of it

anne: what does aria-activedescendent

alice: the host, or a proxy, depending on our direction. you would have to specify it.

anne: what I would like for custom elements is that they are used like regular elements, you don't need to know they have a shadow tree

alice: the cases where you need to refer into it, you now, you do know there is a shadow root

anne: the custom element users shouldn't have to know.

alice: the cases where semmantic delegate would work, that is true. but active-descendent... you know the id is an element in the option list, not the "option list" host.

anne: in that particular case, the option list the elements need to expose some API, it must be part of it's public API. this could probably still happen with delegation. This is a sloted element, that is the example, you can have a reference form the shadowroot

alice: no in this case hte option is inside the shadowroot. it is not slotted.

anne: datalist would have to expose what it's options are in it's API. datalist would say in the public API what it's active option is. well... this needs more thought. I guess you could say, datalist is my active thing. This could be done though the optionlist API. (discussing https://people.igalia.com/alice/shadow-idrefs/#/20 )

alice: my feeling is that... I little less worried about refactoring issue, these things are inherantly dynamic (correct me if I'm wrong component authors) it would be hard to hard code an active descendent. the thing it is referring to is dynamic an dmight change. I'm not sure if could be hard coded in a way.

anne: it would be nice if optlist wanted to use a different option component, then they could just use it.

Benny: would it be useful in a server side rendering scenario, where you can compute the state of the page.

brian: tha tis most of what I was thinking, we have ways to serialize the shadow dom. there is no browser on the server side. if you are reasoning about how to assemble things, cna you need to connect for server side rendering, seems like you should be able ot do that

nolan: I think the exisitng delegating reflection spec address anne's concern. you point the active-descendent at the outermost host, the option list. the one advantage that this has over that spec is aesthetics. it seems weird to point at optionlist instead of option as well.

alice: coming from the non-shadow dom ... you point at the option, not at the option list. it's a weird mental shift to just trust that it will do the right thing.

anne: this is a weird pattern, to me, html made datalist of backwards compat.

alice: it might be recyler view, or loading things from the server. the idea is to not leak all the weirdness of the recyler adding to the light dom.

IDREFs part 2

slides: https://people.igalia.com/alice/shadow-idrefs/#/19

Alice: (presents slides)

Proxy/ElementReference

Alice: with ElementReference you can only get to the internal element if you're browser internal or have access to the shadow root.

Anne: An issue is this can't be serialized. Also, it doesn't match built-in elements in terms of crossing the boundary. It also requires knowledge of the components layer, which users should't need to know.

Emilio: This doesn't work for any IDL attribute that takes an element, but exposing something halfway in a way that you can't point to otherwise... To expose something from a shadow tree, I'd expose an existing mechanism, which doesn't have the serialization drawbacks.

Emilio: From what I understood, anywhere you can have an element, you could use an ElementReference. ... That is very odd, and it gets complicated. But my main concern is, we already have a way to expose elements from a shadow root, which doesn't have the drawbacks of exposing it to global JS.

Alice: Even if we do this magic of an IDL extended attribute to set it to an ElementReference, you would also have to explain that you get back an ElementReference.

Emilio: Internally you would have to preserve the fact that you set an ElementReference, you would have to preserve the JS object internally. And if it's less generic, if this only works for ARIA attributes, I guess that's fine. But I'm not sure how generic you want this to be.

Alice: I would want it to work for any of these things [ARIA relationships, slide 40]. Anywhere that you might have an IDL element attribute, you could use this, so it's generic in that sense.

Emilio: It's not a massive list, but the question mark at the end...

Alice: I might have missed some.

Emilio: Could we target the getters? Same as when the fullscreen element is inside a shadow tree, we return the host; we do the same, so we don't expose the actual shadow tree. If there's a data list on the shaodw tree, and we do the part approach, then if the list attribute points to a thing inside the shadow tree, you don't want to expose the actual shadow tree element, it needs to be targeted to the shadow root.

Anne: Maybe at some point you'd need APIs that give you the part. But with the existing APIs you couldn't do that. But that only applies to the "multiple relations of the same type" scenario.

Emilio: Yes, if we make the delegation work correctly [?]

Anne: One thing that came up with relationships, they all need to be of the inward type. For the outward type, they would need to be refactored(?). We had that with form-associated custom elements.

Alice: You could do form inwards or outwards, because ... [form attribute]

Anne: I don't think we necessarily want to generalize this to all features, we don't want to extend the form attribute

Alice: We don't need to

Anne: If we have a new reference syntax, ID + part, the form attribute shouldn't take that syntax. We should only allow that syntax for relationships where it makes sense

Alice: We're discussing using parts. When you refer into the inside of a shadow root, you have part ... I like that we're reusing an existing context designed to preserve encapsulation. The part attribute can move around, and that's elegant. But when there's no update on the host of an attribute (the element having the aria-descended attribute), you'd have to be careful to spec that a change in that element triggers changes in the accessibility tree in the same way as if the attribute was changed on the host.

Anne: I think that already happens, changing parts changes the AT

Emilio: What about when IDs change?

Alice: I don't believe that is handled. It doens't happen often enough to be a problem. Currently you may get notifications in the AT if an element has an active descendant attribute that changes, that element would have to have the update triggered on it. As opposed to something in a far distant part of the tree that would need to flow in the wrong direction.

Emilio: That has the same complexity as handling ID changes.

Alice: But this is designed to be dynamic and IDs aren't.

Anne: ID changes are dynamic ...

Emilio: ID changes update the AT ...

Anne: I would consider it a bug if the AT doesn't follow ID changes

Emilio: And it has the same implications as part mutating. If ATs don't follow that it's a bug. For the example you wrote, the component would be responsible of changing the part in the shadow root. If you change options, you would remove the ... What would happen is, the attribute is updated with a new ID in the element ... If you remove the shadow DOM from the example, you could do ... set aria-activedescendant to ...

Emilio: Presumably you brought this up because in this example you'd change the attribute off and on, and ... but nothing would prevent ...

Alice: I don't think that works, and I don't think people are doing that. But with IDs and wihtout shadow root, you don't have the same encapsulation problem. The elegant part of this, you have listbox:part(active), which says the active descendant is the one I want. Conceptually, you could say to the listbox, I want to target whatever you say is the active component

Emilio: I don't think dynamic changes should be problematic. We should be doing this for IDs already, and if not it's a bug.

Anne: It's fundamental to the DOM that changes are handled. It'd be interesting to see examples of that not working, and add them to the ARIA test suite, because that's not acceptable to me.

Alice: Maybe I misunderstood and it does work.

Anne: I don't understand the state of the art in certain platforms, but it's possible that they only update their understanding of the world periodically. But the modern ARIA stuff, the browser is more involved in setting the relationships. But there might be gaps.

Alice: In the notes for the web components meetings, part was rejected as an idea. Do you remember why?

Anne: I don't remember what the concern was. Getting clarity on the use cases for the relationships was a problem, especially if they go both inwards and outwards. Emilio seems to share my intuitions that the relationship should only be inwards. Since ARIA only has relationships in the wrong direction in some cases. labeled-by ... There's no corresponding thing in ARIA for going the other way, and same for described-by. But some relationships are more delegation-compatible. So maybe there should just be delegation, and the parts idea... For multiple relationships you would need identification, and that could be solved with parts. For individual parts, you'd need to say which relationship applies to each part. But that could all fit together.

Anne: It also preserves the idea that the shadow root is the boundary, and part is part of the public API that the world talks to. Emilio said this solves the serialization problem if we allow parts in references.

Ben: I do like the idea of being able to use the shadow host boundary to export/import some sort of IDREF like part, one problem is that this has multiple partners. We can try to define something new, that you can export and import IDREFs into a shadow tree.

Emilio: I thikn to me at least, it doesn't seem super worth having another name for this. Browsers have to deal with multiple elements having the same ID or exposing the same parts. The only thing a new name for this would mean, is that each element needs to have one part name. Though that might not be great. We need to disambiguate anyway between 2 elements with the same part or ID (presumably the first in DOM order); having a new name might be a bit overkill.

Ben: My point is that it has a different use case, so you might use parts for CSS styling, but you're not using them for IDREFs.

Anne: I think that's fair. The worry is that you need to do more work as a developer. If you're making this stylable, you need to export both. But you might not need that, in the input control example. You don't want the input control stylable from the outside.

Emilio: If you can export as an IDREF is probably to expose it for styling.

Anne: Fro the simple case you don't need to expose it at all because there's delegation. No, you still need to identify which element.

Emilio: You can use IDs in the shadow tree.

Ben: Thinking on having a new concept, like importID; you say aria-labelby something and it can be something outside of the shadow tree.

Emilio: That's part of the discussion from earlier. The label should say "aria labels my component" [?]

Ben: In that case you'll be defining an ARIA proxy???

Anne: Emilio and I's agreement on this, is some ARIA relationsihps go in the wrong direction. If we switch them, we only need to solve the delegate direction. We don't need what was sometimes called reflection or exporting. We'd only need to solve the inward case.

Ben: That's an interesting idea, haven't thought about that and if it's possible to do that.

Alice: I think it depends on whether any of those attributes there's a direction that it needs to go, if you are going in the wrong direction. The question could be that if any of those attributes do any of them tend to go both ways. Do you have two attributes in both directions and use the one you need? ... How valid is that intuition?

Anne: If adding the inverse solves it for all, it works.

Ben: An example, if we have the x-label component and an input, you might need to go in both directions. x-label, if you want to use a for attribute in the label itself, it'll have to... how do you do this? Not sure if that makes sense

Anne: Not sure how the tree is.

Emilio: The tree is an x-label component with a label inside of the shadow tree. A sibling of the x-label could be a x-input with an input inside the shadow tree.

Anne: For that case, we should design a way to label things. Much like form-associated elements we should have ... label elements.

Ben: I assume we might need some of this for other attributes.

Anne: I'd love an example.

Ben: describeby. Like x-description element that has something inside. I'm trying to come up with a better example.

Anne: One of the things I've been asking for is examples in both directions.

Alice: My undestanding is that the viability of the part solution. It seems elegant to referring in. If you don't need to refer out in a serialized way, is that resanoble?

Emilio: I think so.

Anne: I think it can be still be a good solution, if outer references is really a thing we can design.

Alice: Completely agree.

Anne: I feel this solves all the use cases I've seen so far.

Emilio: Presumably assuming the ... relationship, as label-by ...

Anne: For the label we might need a better solution, as labelby doesn't do anything when you click in it. And we might want that to happen.

Ben: There is label for.

Anne: There's label for, but you still need some kind of default support for custom elements, when it points to a custom element we need something special there.

Alice: I think what we need to do is write up this parts idea. I'll try to do that, if you feel like I got the gist of it in this slide.

Anne: I feel the part part is really about handling multiple relationship, and there's another aspect; what if there are no parts and you want to delegate the relationship (that also needs something). parts is useful if your controller is so complex that you need multiple relationships (2 inputs and 2 label elements that need to point to them). Another thing could be a specific thing, if there are strong enough cases that you want to export ID parts that you want to export for styling things.

Emilio: If you don't need to export from a nested shadow root... What parts provide on top of ID is you can re-export parts from nested components. Instead of parts we can use IDs if we have some way to export them. But that's for exporting a stylable but non-referenceable element.

Anne: We could also have some nice way of doing it with part IDs or something like that.

Emilio: As long as we agree on the general directions, that you reference the ID of the element, and the ID of the part/thing, then it should be workable.

Alice: I'd try if the 3 of us can get something written down about this parts idea. Having a default part, that one element is referred if someone refers (like the semantic delegate idea); your intuitions about references going only in one direction; things that you cannot do right now with the available APIs, but things that are using the existing element IDL attributes to referring from ShadowRoot out. Back to this list of relationships, how even it's being used in non ShadowDOM HTML; take pages that are using these things, and non-shadow DOM components that are doing this things and don't need the encapsulation boundaries; and draw the directions of those relationship.

Anne: I think it'd generally work. With the label example, sometimes it shows something like we need to do a form associated custom element, like a label custom element. For popover target we might need one for button, and popover target should be still able to refer to part. I think the uses cases I've seen for popover targed could be addressed. Currently it can only be used in a button like element, but if you allow a custom element to be a button.

Anne: We need to export from the parent perspective. And we probably not one to one in some cases. When you have parts...

Alice: Any last thoughts on jitsi.

Ben: Do you think it'd be welcome to write something about a IDREF idea I have?

Anne: I think it's worthwile to have counterarguments for why using part would be not great.

Alice: That would be fabulous.

Anne: Especially if you have particular components where you can explain here we want to export this element, but we don't want it to be stylable.

Alice: That's a very good point. Ben, if you would write a gist it'd be great. Then I could file an issue to centralize these discussions. Send me a link or put a link on the Hackfest issue. But it'd be very welcome if you would write that.

Ben: Not sure about the best place for this. Anyway, I'll write this.