The current state of web forms
Or: ‘Why UI libraries exist’
In working with web forms, the same sorts of edge cases seem to appear repeatedly, and (at least) I find myself waffling on how to approach them with JavaScript.
I feel better not reinventing the wheel, and just normalizing the cross-browser differences.
It's hard to avoid reinventing the wheel
The timing and intercepting of validation events feels hacky at best, yet I feel sloppy ignoring the browser's built in input validation. That being said, input validation is not consistently supported, not does it behave predictably. Also the UX leaves a lot to be desired, with forms opting to wait until an entire form has been submitted, rather than validating inline.
Binary validation isn't enough
The form and input specs only provide 2 values for validity state: :valid and :invalid, which are only evaluated after the input has had onBlur triggered as a target, unless it's also marked as :required which is evaluated on submit as :invalid.
However: this is not always true.
"an empty string means the constraint is satisfied".
I have seen folks like @joshblack use Objects like Enums with 4 states, which seems like a much better idea.
'valid' | 'invalid' | 'validating' | 'initial';
We have CSS pseudo-classes for things like :out-of-range for min- max ranges, and :indeterminate for half-filled checkboxes, but not a breakdown of pseudo-classes for validity of initial states.
DOM validation APIs
The DOM method of event.target.validity is read-only, as is the ValidityState method. The latter is a real bummer, because that could be super useful.
You can only read from checkValidity() as well. There's no programmatic way in the browser to force set a field's validity.
Update: I was wrong about this. Here's how you force the browser to apply :valid and :invalid on your terms.
In a handful of browsers, setCustomValidity() sounds like a great idea, ~~but it's only setting the content of the browser's default field validation message.~~
Any non-null value passed as a parameter to setCustomValidity() applies the browser's :invalid CSS pseudo-class.
field.setCustomValidity("This field can't be empty");
To restore the browser's :valid CSS pseudo-class, pass an empty string to setCustomValidity().
field.setCustomValidity("");
Do note, however, that this API is not universally-supported across every browser, but it still has enough to justify inlcusion.
The other curious property is HTMLInputElement.validationMessage. This is yet another read-only property, that only appears while hovering over an invalid element.
You cannot set it, though it does change. It's an empty string when the input is valid, but the browser sets it again when it's invalid. It's a "getter". There's not even an error when you attempt to set it, at least in the console, anyway.
"There is no standard way to change their look and feel with CSS."
Sure, you can start juggling classes like .invalid, .required, etc. but I can assure you: that is a guaranteed path to madness.
What about accessibility?
None of the aforementioned even touches how radically-inaccessible all of this is. Because of all the wheel reinvention needed to make inputs a reasonably-painless experience and consistent across various contexts, we've totally munged the native affordances given to us by HTML. This leads devs who care and notice to start applying attributes like aria-live, and accessibility experts to pull out their hair.
We have to do better.
Smarter defaults
Here are some ideas on how to improve developer and user experience at the W3C standards level.
- Automatically disable
autocorrect,autocaptialize, onemail,url,password, and every otherinput typethat isn'ttextorsearch.
Ditch
placeholder, repurpose them to static input masks.
Improve the email type validation regex. The pattern in the spec
/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
allows this:

Search the web for all of 5 seconds and you'll find a better regex. Like this one.
[a-zA-Z0-9_]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?!([a-zA-Z0-9]*\.[a-zA-Z0-9]*\.[a-zA-Z0-9]*\.))(?:[A-Za-z0-9](?:[a-zA-Z0-9-]*[A-Za-z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?
Ditch
passwordmasking. At the very least, include ahide passwordUI control that browsers can safeguard against saved password exploits.- Use this same input type for captchas.
- Introduce
input type="fingerprint". Native mobile operating systems are already doing this.
Introduce UI counterparts on the Web for inputs that were born on native mobile interfaces.
- Toggles. Binary—on or off.
- Segmented controls. Perhaps a type of
radiobutton orselect. geolocationinput type. We already have geolocation APIs. Why not standardize the inputs?stepattributes could allow finer-grained controls.- Default form CSS to mobile-first styling
- Large, separated touch targets
- Picker menus instead of separate
inputs formonth,day,time, etc.
Make time data more intelligent
- Introduce
birthdatetypes that automatically setmaxto youngest acceptable age for a given site's terms of service, avoiding "are you really from the future?" messages.
- Introduce
- Define consistent relative times and dates for
timeinputs and elements. See moment.js for a great example of what a baseline API for this should look like.
Provide validation APIs more control and much less boilerplate when it comes to custom client-side validation.
- Define validation errors as attributes on input elements
- Add the option to specify custom messages per ValidityState, including defining custom ones.
Allow the developer to choose when validation occurs
- Default to inline validation with a 2 second debounce, and/or
onBlur()
- Default to inline validation with a 2 second debounce, and/or
Allow overriding CSS for browser validation error message popovers
Introduce
cameraandmicrophoneinput types to make speech and media input easier.Explicitly separate
valueand addinitialValue(see React.js'sdefaultValueattribute for why this makes sense). TL;DR: Check what happens when you set an initial value for an input that doesn't match a pattern. For example:
- Eliminate the confusion created using scenarios such as the following:
<input type=text inputmode=numeric>(triggers numeric software keyboard) vs.<input type="number">(does not trigger numeric software keyboard)
<input type="number">should automatically haveinputmode="numeric"andpattern="[0-9]*" set, and thestepUI should be explicitly enabled/disabled.
Don't force
inputelements to be wrapped bylabelelements to gain larger hit areas. Accessibility: yes! Markup hacks: no!<input type="emoji">. With the number of "reaction" UIs cropping up, this only makes sense.Consider custom keyboards Sure, it seems scary, and lots of dangerous things could be done. All I'm asking is to consider it. There is also a lot of good that can be done as well.
What do you say, W3C?
These are just a few improvements and suggestions for better developer and user experience. Let's make them happen. Add your voice in support here: https://discourse.wicg.io/t/the-current-state-of-html-forms/1478
Hi.
Overall I think you effectively demonstrate some of HTML forms' weaknesses, and I think you suggestions are mostly valid. However, I do feel that you've glossed over the power of the
patternattribute, which can be used for minimum lengths and maximum lengths like so:(Min-length of 1, no max-length)
(Numbers only, min- & max-length of 4)
The
patternattribute is also useful for preventing empty strings from appearing valid if they are not required.Generally speaking, input validation can be deactivated or circumvented by the client (in theory) and thus validation must always be implemented on the server. This makes Ajax the primary, best method for submitting forms—which means that a form solution will involve a fair bit of JavaScript anyway, and a UI library is generally useful (though I tend to use plain JS).
Why would you want to set autocorrect and autocapitalize on email/url/password input fields? This seems like a really bad idea.
Excluding Android's default browser, which mobile browser does not have its software keyboard triggered by
type="number"? And can this not be addressed by addingpattern="[0-9]*"for cases like the default Android browser?I would be tempted to agree with this if it wasn't the responsibility of Safari to prevent form submissions on pattern violation. Then it would be important to use
type="number"to validate numeric-only input and thusinputmode="numeric"would be useful to control the software keyboard. However, since it is the responsibility of browser vendors to implement the standards properly, I do not think that this even bigger task of implementinginputmode=xis really the best way to go. It certainly seems very idealistic.The simpler solution would seem to be for browser vendors to trigger the numeric keyboard for
type="number"and not forpattern="[0-9]*".Wouldn't not using
passwordmean that the browser autocompletes and stores your password without notifying you? There is a reason the password is hidden when you enter it.Good point. Updated to reflect.
The best solution I found is O(n) and it uses no extra space. It is similar to inorder traversal but instead of storing it to array and then checking whether it is sorted we can take a static variable and check while inorder traversing whether array is sorted.
مافهمتهة كلهة بس شكراً