Use `:invalid` to style a form field when its current value fails the rules set by its HTML attributes. A required field is invalid when empty; an `input` with `type="email"` is also invalid when its value is not an email address. section 10.8
Show an error beside a field
A name input can use `required`, `maxlength="250"`, and `aria-describedby="nameError"`. Keep the referenced error container in place, hide its message `<span>` by default, then reveal the span when the adjacent input matches `:invalid`. Hiding the span rather than its container preserves the programmatic connection to the error. section 10.8
`:invalid` can match before someone has touched a field. To avoid showing an error immediately, the error-handling selector also requires a `dirty` class: `.dirty:invalid + .error span`. The field-border rule uses the same combination. `:user-invalid` offers an interaction-aware alternative, but the cited browser-support limitation leads to using JavaScript for that timing. section 10.8
Listing 10.21 Error-handling CSS
.error span { display: none; } #1
.dirty:invalid + .error span { #2
display: inline; #2
} #2
:is(input, textarea).dirty:invalid { #3
border-color: var(--error); #3
border-image: none;
} #3
The CSS listing shows the hidden message, its conditional display, and the invalid field border together. section 10.8
Pair error color with a visible message and icon rather than relying on color alone. Keep focus styles as well, so the form remains usable when navigating by keyboard. section 10.11 section 10.8
