Re: [w3c/webcomponents] [Shadow] activeElement behavior seems to break encapsulation (#358)

I still think that `shadowRoot.activeElement` shouldn't point to something outside that ShadowRoot: `shadowRoot.contains(shadowRoot.activeElement)` should be true unless `shadowRoot.activeElement` is null. Also, I now agree that changing the API of `activeElement` to include slots (even though this is a new context) probably isn't ideal because it seems natural to assume that `activeElement` always returns a focused element with a useful `focus()` method, if any. A new property sounds like a better way to handle finding the 'deep' (non-slot) active element. For the same reason I opened this issue, I think it this new property still shouldn't directly reference a node in an arbitrary ancestor tree of the ShadowRoot, but should work like [the alternative proposal here](https://github.com/w3c/webcomponents/issues/358#issuecomment-202256430) instead.

Maybe this property could be called `activePath` (or `activeDescendant`)? Given that a slot acts as a 'Shadow DOM boundary' and can reference elements distributed within it, I think it makes sense to put a property of the same name on slot. Then, you could still follow this property from any ShadowRoot or slot and eventually reach the lowest focused shadow-inclusive ancestor that is contained within that ShadowRoot or slot's composed tree. (Assuming I've got the right understanding of 'lowest shadow-inclusive ancestor'..) For example:
```
function getDeepActiveElement(start) {
  let end = start.activePath;
  while (end && end.activePath) {
    end = end.activePath;
  }
  return end;
}
```
`getDeepActiveElement` would take a ShadowRoot or slot (`start`) and end up at the 'deep' focused element (`end`). `end` would always be a non-slot, focused descendant of `start`'s composed tree, unless `start.activePath` was null. Additionally, if `start` is a slot, there's a nice similarity with `activeElement` where there's always 0 or 1 elements `x` of `start.getAssignedNodes()` for which `x.contains(start.activePath)` and 0 or 1 elements `x` of `start.getAssignedNodes({flatten: true})` for which `x.contains(end)`. However, I don't think it would be appropriate for anything other than Document, ShadowRoot, or slot (i.e. anything that could host a ShadowRoot) to have this property because `getDeepActiveElement` would then take you inside those hosts' ShadowRoots.

IMHO, ShadowRoot should only provide access to things within itself, with the notable exception of the reference back to its host. Slots seem like a better place to access things distributed into the ShadowRoot from outside, but these accesses should be restricted to the portion of the ancestor tree that was assigned to the slot. If someone wants build a component that reaches elements *outside* of a ShadowRoot's composed tree, it should be up to them to get there by going up through the component's host through something like `parentNode` and not down through the ShadowRoot or its slots. These APIs should lead you to the boundaries provided by ShadowRoot and slot, but then require you to explicitly step across those boundaries.

---
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/358#issuecomment-202655660

Received on Tuesday, 29 March 2016 01:27:08 UTC