-
Notifications
You must be signed in to change notification settings - Fork 124
Shadow DOM support #196
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
Shadow DOM support #196
Conversation
This change enables custom elements to coordinate with the polyfill in order to apply it to discrete scopes of the composed tree (such as shadow roots).
src/focus-visible.js
Outdated
| loaded = false; | ||
| document.addEventListener('DOMContentLoaded', load, false); | ||
| window.addEventListener('load', load, false); | ||
| // We detect that a node is a ShadowRoot by ensuring that it is a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Putting this comment inside the previous if block is breaking my brain a little bit, though I can see why you did. Maybe switch the order of these if/else statements? It would be marginally less efficient for the "normal" case, I guess, but more readable.
Or, perhaps a switch statement over scope.nodeType ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @alice I'll try to rework this so that it is less of an eyesore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched the order of the conditions around. The comments are hopefully more cleanly formatted now.
| return matchesMouse(false); | ||
| }); | ||
|
|
||
| describe('focusable elements in shadow', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this test is failing in CI for some reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about that, will take a look
|
Generally looking really good (that gif blew my mind), not sure what's going on with that test though. |
|
Just had a quick look into the test failure. Looks like it's failing in Firefox due to some interaction between the shady dom polyfill and the focus-visible polyfill. |
|
I have addressed the test failures. The following changes were necessary:
|
|
Aww, no commit history? We squash merge anyway. I can't tell what's changed since I last looked :\ |
|
Sorry, I will try to recreate the history |
|
Thanks and sorry :\ |
|
Nothing a little git gymnastics couldn't handle 👍 I split the change out into two commits. It looks like the Node.js 10 build had three test timeouts this time around. I'm not sure if that is actionable... |
| } else if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) { | ||
| // We detect that a node is a ShadowRoot by ensuring that it is a | ||
| // DocumentFragment and also has a host property. This check covers native | ||
| // implementation and polyfill implementation transparently. If we only cared |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the added counterfactual here, thank you!
| if (self.ShadyCSS == null || self.ShadyCSS.nativeShadow) { | ||
| applyFocusVisiblePolyfill(el.shadowRoot); | ||
| } | ||
| }, { once: true }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL 😲
Since 2016, even!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
|
Thanks so much for the git gymnastics! Build problems look like they were an infrastructure problem, it passed once I restarted it. |
|
@robdodson LMK if I can do anything to help move this one forward! |
robdodson
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation looks good to me, thank you for writing the tests!
I just had a couple of comments regarding the README.
README.md
Outdated
|
|
||
| ```javascript | ||
| // Check for the polyfill: | ||
| if (self.applyFocusVisiblePolyfill != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is self equivalent to window? Not sure if the snippet makes it clear what context this is running in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, self is equivalent to window in the document context. I can change this to window.
README.md
Outdated
|
|
||
| ```javascript | ||
| window.addEventListener('focus-visible-polyfill-ready', | ||
| () => self.applyFocusVisiblePolyfill(myComponent.shadowRoot), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to above, what's the expected value of self in this context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will change to window.
|
I think this is good to merge once chris makes the |
|
@robdodson README has been updated per your request 🍻 |
| try { | ||
| event = new CustomEvent('focus-visible-polyfill-ready'); | ||
| } catch (error) { | ||
| // IE11 does not support using CustomEvent as a constructor directly: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it support new Event()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some very light Googling yields this Stack Overflow that suggests "no" and "use CustomEvent instead" 😄
Shadow DOM support
This change enables custom elements to coordinate with the polyfill in order to apply it to discrete scopes of the composed tree (such as their shadow roots). Highlights include:
windowas a function that can be invoked on anyDocument|ShadowRootdocumentwhen its script runs, preserving the existing behaviorShadowRootcan apply it as neededdata-js-focus-visibleattributefocus-visible-polyfill-readyevent is now dispatched onwindowto support lazy loading scenarios (see discussion in Is DOM ready necessary? #193)Example usage as a mixin
In the course of implementing this proposal, I also crafted a mixin to demonstrate how a custom element should coordinate with the polyfill in order to take advantage of
:focus-visible-like capabilities.I am not proposing to include the mixin in the main project, but it is linked here for future reference:
https://github.com/cdata/focus-visible/blob/fc33395294dd69ad8af70e822e6176a8893816e2/src/custom-element-mixin.js#L1-L49
Compared to #112
There is an older WIP proposal (#112) up for consideration that attempts to add transparent support for arbitrary shadow roots. This approach would ultimately require that
focusandblurbe observed at every shadow boundary throughout the composed tree in order to work transparently.The design in the proposal before you expects a Shadow DOM-using component author to opt-in to the polyfill. This allows the polyfill to be applied to Shadow DOM-using components that need it, while avoiding the cost of observing changes in shadow roots that do not know about or do not want to use the polyfill.
Examples
For the purposes of the following examples:
:focuselements are styled with purplecolorandborder-color:focus-visibleelements receive the default focus ringdelegatesFocus: trueconfiguredShadow root styling problem
Without this change, it is not possible to use the polyfill from within a shadow root. In the following example, you can see that the top-level document elements can be styled to hide the focus ring when focusing with pointer events, but focusable elements inside of a shadow root still display a focus ring:
Fixes #193
Fixes #28
Fixes #112