The :has() relational pseudo-class matches an element when a selector relative to it matches. It can express a parent-child state relationship in CSS.
CSS :has: style a parent from a meaningful child state
How the rule works
A receipt field wrapper needs a stronger border when the input inside it is invalid. The wrapper rule can look for that native state, while the input remains the element that owns validation. Scope the search to a small component instead of writing a document-wide rule that relates distant content. The wrapper should not become the only error message; include visible error text after a rejected submission. A blank required input may match :invalid before the person has tried to submit, so decide whether the timing matches the product's feedback policy.
.receipt-field { border: 1px solid #71869a; padding: .75rem; }
.receipt-field:has(> input:invalid) { border-color: #9b3030; }
.receipt-field:has(> input:focus-visible) { outline: 2px solid #205c8a; }Cost and verification
The selector adds no JavaScript or network transfer. It can still cause more style matching than a simple class when used broadly, so profile an actual large page before making a performance claim. Test supported browsers and an unsupported-browser fallback: the base border remains usable even when :has is ignored. Keep the native input's own focus indicator as well, since the parent outline may not be close enough to identify the focused control.
Common Mistakes
- Do not use :has as the only source of validation text.
- Do not apply a broad relational selector to every element on a large page without measurement.
- Do not remove the input focus indicator because its wrapper now changes.
Connected lessons
- CSS Selectors
- CSS pseudo-classes: style interaction states without hiding them
- CSS focus-visible: keep keyboard location unmistakable
- HTML aria-invalid: connect a failed field to a repair instruction
