WebCraft

:has()

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.

CSS
/* the parent selector we waited years for */
.field:has(input:user-invalid) {
  border-color: #e06c6c;
  background: rgba(224, 108, 108, .07);
}

Published

Questions

<details name>

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.