A wrapper that knows its input is wrong
CaveatSpecificity is taken from the heaviest selector inside the brackets, not from :has() itself. Put an id in there and the whole rule inherits an id-level weight you did not intend to spend.
FallbackPair it with :user-invalid, never :invalid, or the wrapper is red before anyone has typed. Without :has() the field simply stays neutral.
/* the parent selector we waited years for */
.field:has(input:user-invalid) {
border-color: #e06c6c;
background: rgba(224, 108, 108, .07);
}
Published
Questions
What specificity does a :has() rule have?
:has() adds no weight of its own — it takes the highest specificity of whatever is inside the brackets, the same way :is() and :not() do. Put an id in there and the whole rule inherits an id-level weight you did not mean to spend.
Can I style a label or wrapper based on the input inside it?
Yes, that is what :has() is for: the wrapper matches on the state of a descendant, so the field, its label and its border can all react to one invalid input without a class being toggled from JavaScript.
Should I pair it with :invalid or :user-invalid?
:user-invalid, always. :invalid matches from page load, so the wrapper goes red before anyone has typed a character. Without :has() support the field simply stays neutral, which is the safe way to fail.