-
Notifications
You must be signed in to change notification settings - Fork 130
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
Focus trapping fails to account for elements within shadow DOM #322
Comments
Good evening Eli! Thank you very much for opening an issue. I am sorry to hear you are facing issues with the implementation… 😔 A pull-request would be most welcome (provided it doesn’t inflate the library size out of proportions that is). Do you have any idea how you plan on fixing it yet? I must say I know very little about web components and shadow DOM, so I’m all ears. :) |
Great to hear! Admittedly, this stuff is relatively new to me as well. I've done some initial research and found https://github.com/salesforce/kagekiri, which provides "Shadow DOM-piercing query APIs". At this point, I'm assuming we could pull the relevant logic out of that library or use it as a guide for implementing the specific methods we need in That said, I'm realizing that basically anywhere |
I was trying to use a11y-dialog with templates and slots, but was hit by this issue. I'm happy to see it here. I ended up reimplementing a lot of it, and in the meantime I wrote something that might help you as well. /**
* @param {string} selector
* @param {DocumentFragment | Element} root
* @returns {HTMLElement[]}
*/
export const piercingSelectorAll = (selector, root) => {
const result = [];
// matching the root against the selector
if (root instanceof HTMLElement && root.matches(selector)) {
result.push(root);
}
// matching the root's children against the selector
const children = /** @type {HTMLElement[]} */ (
Array.from(root.querySelectorAll(selector))
);
result.push(...children);
// matching shadowRoot's children against the selector
for (const element of result) {
if (element.shadowRoot) {
result.push(...piercingSelectorAll(selector, element.shadowRoot));
}
}
return result;
};
const slots = Array.from(this.querySelectorAll("slot"));
const assignedElements = slots.flatMap((slot) =>
slot.assignedElements({ flatten: true })
);
const selectableElements = Array.from(
new Set(
assignedElements.flatMap((element) =>
piercingSelectorAll(focusableSelectors.join(","), element)
)
)
); So then the function $$(selector, context) {
return selectableElements.filter(element => element.matches(selector))
} I hope you find it useful. :) |
Hello, I have the same use case--a web component that I'd like to use a11y-dialog to build. Is this being worked on by anyone? If not I'm willing to give it a go, but I don't want to duplicate effort. Thanks! |
Having only limited knowledge of shadow DOM, I am not personally working on this, but I’d be open to a pull-request. :) |
Most likely will be addressed in v8. |
We are building a web component that uses a11y-dialog—this is similar to the framework implementations of the library but for web components.
We've noticed that focusable elements within shadow DOM are not picked up by the logic in
_maintainFocus
. This is becauseevent.target.closest
is not able to see into shadow DOM.I'm wondering if you're open to a PR (and/or collaboration) that would upgrade this logic with shadow DOM support so this library can work properly with web components.
Thanks in advance!
The text was updated successfully, but these errors were encountered: