feat: add self-hover variant for direct pointer hover only - #20442
feat: add self-hover variant for direct pointer hover only#20442seb-jean wants to merge 1 commit into
self-hover variant for direct pointer hover only#20442Conversation
Add a new `self-hover` variant that only triggers when the pointer is directly over the element, ignoring :hover propagated from an associated <label for="..."> element. Generated CSS: `:where(:hover) > &:hover` wrapped in `@media (hover: hover)`. The :where(*:hover) parent guard ensures the element's direct parent is also hovered, which filters out browser- propagated :hover from label associations (since the label is a sibling, not an ancestor of the input's parent wrapper).
e5e6309 to
8c09e6d
Compare
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. WalkthroughAdds a Merge Risk: ⚪ Minimal · up to This PR adds a localized 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Confidence Score: 5/5The PR appears safe to merge, with its documented shared-parent limitation matching the generated selector’s behavior. The new variant compiles to the intended parent-and-element hover selector, is exposed through IntelliSense, and has focused output coverage; no concrete unacknowledged failure remains. Reviews (1): Last reviewed commit: "feat: add self-hover variant for direct ..." | Re-trigger Greptile |
|
Hey! I appreciate the PR, but this only solves the problem if you are using a specific HTML structure. If you are using the nested approach, then it works as expected: <label class="flex max-w-sm flex-col p-8">
Label
<input type="text" class="border p-2 self-hover:text-red-500" />
</label>because of the child/parent relationship requirement. But many people using a non-nested relationship and use a for/id attribute setup instead: <div class="flex max-w-sm flex-col p-8">
<label for="foo">Label</label>
<input id="foo" type="text" class="border p-2 self-hover:text-red-500" />
</div>For this markup, the solution doesn't work. I don't think we should add generic solutions for specific problems. So I would suggest to add this solution to your own project instead where you can guarantee that you are using the first flavor of HTML markup: @custom-variant self-hover {
@media (hover: hover) {
:where(*:hover) > &:hover {
@slot;
}
}
}Tailwind Play: https://play.tailwindcss.com/aSx5mf663g |
|
Ah, that's a shame; I'm using plain HTML and wanted to replicate the same behavior as the Catalyst example (https://catalyst.tailwindui.com/docs/input) without necessarily having to create a custom variant. |
Summary
When a
<label for="id">is hovered, browsers (Chromium, WebKit) propagate the:hoverpseudo-class to the associated form control. This meanshover:utilities on inputs, checkboxes, selects, etc. trigger even when the pointer is over the label text, not the control itself.The new
self-hovervariant solves this by generating a selector that requires the element's direct parent to also be:hover:When the pointer is directly over the input, both the input and its parent wrapper receive
:hover. When:hoveris propagated from a<label for>, only the input receives it — the parent wrapper does not, because the pointer is physically elsewhere. The:where()wrapper keeps the parent selector at zero specificity.The form control must have a parent wrapper element. If the input and label are direct siblings with no wrapper, the parent is shared and
self-hoverbehaves likehover.Test Plan
<label for>)