w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.42k stars 647 forks source link

[css-selectors-4] `:user-invalid` and `:user-valid` should not require a blur event to trigger #9583

Open argyleink opened 9 months ago

argyleink commented 9 months ago

I think we should remove this line from the spec: and changed the focus to another element.

The goal of this selector is to signal a user has actually touched (focused in) and changed the value of the input. It has nothing to do with blur or moving to another input. It's more about a hook for authors to know it's a good time to show the validity of the input because a user has "tried" something.

Before :user-valid, the signal was premature, sent on form load, before a user has had a chance to interact, showing errors states when they havent even done anything.

https://codepen.io/web-dot-dev/pen/wvNJGrO

In the above demo, each input is empty and invalid. Type some information, it becomes valid, but should additionally be user-valid, not awaiting blur to trigger. Furthermore, browsers do the proposed behavior in this issue, but only after blur; meaning subsequent interactions with the input do realtime trigger user-invalid and user-valid. I'm proposing this is how it always is, and isn't gated by a one time blur event. I'm also pointing out that the implementations from browsers seem confused on the spec prose as well, only respecting the "changed focus" clause on interactions before blur, not after. This proposal change would make the behavior consistent and more desirable to authors.

josepharhar commented 9 months ago

@nt1m

bramus commented 9 months ago

If the "change focus" part gets removed it would need some other trigger to activate: you definitely don't want the email input to nag about it being invalid while you are still typing in your e-mail address (as that would defeat the purpose of the selectors).

What could work is adding some debounced activation that triggers after one has stopped interacting with the control (e.g. pause typing). That could be in addition to blurring it.

nt1m commented 9 months ago

I cocur with @bramus. :user-invalid / :user-valid are linked to the change event because that's when the value is committed. Doing it on every keypress would be very disruptive for users. An alternative definition could use debounce as @bramus says but it would generally be harder to define with not necessarily huge benefit.

The CSS spec says "and changed the focus to another element". I think that's not necessarily always accurate and should probably say something like "has committed a new value" or such. But I don't think that sentence matters a lot either way since it's an example and not normative.

argyleink commented 9 months ago

on every keypress would be very disruptive for users

but it still does this, just after the initial await for blur. should it stop doing that then, and always be blur?

https://github.com/w3c/csswg-drafts/assets/1134620/e6668285-9175-4eff-be2b-205c83132b96

i expect :user-* to be tied to users interacting with it, not "completing" their edits or "leaving" the field.

for a while now javascript libraries have offered even more queues (dirty, touched, pristine) for authors to use, css is barely catching up and doing mixed things

nt1m commented 9 months ago

This is something @pxlcoder and I discussed, and we think it's better for users to get live feedback when they are correcting their values, but just not when they are initially typing it. If we always waited for a blur even after the initial value was typed, it'd be actually be annoying to the user to not get feedback on whether the correction is valid.

:user-valid / :user-invalid are just meant to address the annoyances of :valid / :invalid. Its definition is solely based around that.

SebastianZ commented 9 months ago

UX is key here and it looks like browsers have different approaches to this.

Here's a simple test case similar to @argyleink's one: https://jsfiddle.net/SebastianZ/6mrojuet/ They differ when the value is valid, you blur, then focus again and make the value invalid again. In that case, Chrome matches :invalid, :user-invalid while Firefox matches :invalid, :user-valid. So Firefox tries to be smart and resets the behavior back to the initial one in case the value gets invalidated when the user focuses the field again. Though when it's the other way round, i.e. the value is invalid, you focus the field again and enter a valid value, :user-valid matches immediately. (Maybe someone can provide the behavior in Safari to see whether it behaves differently.)

From the user's perspective, I believe Firefox' behavior makes sense.

It should be clarified whether there are use cases in which authors need control over that behavior. And regarding debouncing, I want to point out that some users type slower than others. So people might then get a different UX depending on their writing speed. I don't believe that's something desirable.


That aside, if we decide that authors should get more control over that, one way to address this would be adding :valid() and :invalid() pseudo-class functions which take a parameter defining the behavior, e.g. dirty, touched, and pristine as @argyleink mentioned.

In that case, we should then also think about extending the Validation API so that Web Components can make use of that as well.

Sebastian

SebastianZ commented 9 months ago

Btw. there's also a separate discussion in #1533 about adding a pseudo-class matching when a user has changed the field value.

Sebastian