The user-invalid CSS peudo-class allows you to display styles when an input is invalid. This is different than :invalid, because it will only trigger after a user has interacted with it. You can also combine it with :has() or the sibling selector to show/hide error messages.
This is currently available in Firefox, and Safari (16.5), and will be in Chromium 119.