LibWeb: Support :host::part() selectors within shadow DOM stylesheets

The :host::part() pattern allows a shadow DOM's own stylesheet to
style its internal elements that have been exposed via the part
attribute. Previously, ::part() rules were only collected from
ancestor shadow roots (for external part styling), but never from the
element's own containing shadow root.

Fix this by also collecting ::part() rules from the element's own
shadow root in collect_matching_rules(). Additionally, fix the
selector engine's ::part() compound matching to preserve the
shadow_host when the rule originates from the part element's own
shadow root, allowing :host to match correctly in the same compound
selector.

This fixes 2 previously failing WPT tests:
- css/css-shadow-parts/host-part-002.html
- css/css-shadow-parts/host-part-nesting.html
This commit is contained in:
Andreas Kling
2026-03-21 16:42:21 -05:00
committed by Andreas Kling
parent 3b1bbd7360
commit 223ca14abc
Notes: github-actions[bot] 2026-03-22 02:43:58 +00:00
7 changed files with 53 additions and 11 deletions

View File

@@ -1204,10 +1204,17 @@ bool matches(CSS::Selector const& selector, int component_list_index, DOM::Eleme
element_for_compound_matching = *context.part_owning_parent;
context.part_owning_parent = nullptr;
// Also have to update the shadow host we're using.
if (auto shadow_root = element_for_compound_matching->containing_shadow_root()) {
shadow_host = shadow_root->host();
} else {
shadow_host = nullptr;
// If the rule comes from the element's own shadow root, we're matching
// :host::part() from within the shadow DOM's own stylesheet.
// Keep shadow_host as-is so that :host can match.
auto is_internal_part = context.rule_shadow_root
&& context.rule_shadow_root == element_for_compound_matching->shadow_root();
if (!is_internal_part) {
if (auto shadow_root = element_for_compound_matching->containing_shadow_root()) {
shadow_host = shadow_root->host();
} else {
shadow_host = nullptr;
}
}
}
}