HTML Form Validation is underused(expressionstatement.com) |
HTML Form Validation is underused(expressionstatement.com) |
Call spade a spade. Don’t call it heavily underused.
It's just that for the demos in the article it makes sense to show invalid states as soon as possible, but for a nicer UX in real apps you need to take into account "touched" and "submitted" states for the form and per input
For the demos I wanted the reader to know at a glance when our validation code takes effect and this obviously comes at a conflict with demoing a fully "real-world" behavior
Ideally constraints would also propagate from model definitions, so there could be a single source of truth for "what phone numbers do we accept". Some years back I tried to do this by parsing SQL table definitions, but never got far enough. Django does this, but it lacks pretty much any client-side validation support IIRC. (Or client-side anything, really...)
With Typescript, this is now my preferred way to build full-stack sites.
You still need to handle the "what happens next" part on each side, but at least your validation rules are shared.
No. Don't use the maxlength attribute.
https://adamsilver.io/blog/dont-use-the-maxlength-attribute-...
I also dislike the "character rejection" mechanisms, even though many people love it and products often ask to implement it.
To add to the possible solutions mentioned in your article, I'd add the "pattern" attribute. You can do something like this:
<input pattern=".{0,6}" />
This will allow input of any length, but show a warning then the value is longer than six characters.
Capturing input with frameworks is much simpler than pulling the values out of an event object, so I'd be okay with just using input and button elements.
Yet, that doesn't trigger the validation, so I end up wrapping it with a form element and using a submit button.
I run the validation manually using `reportValidity()` on `element.querySelector(...)` before passing it on to whatever.
I do miss when textboxes had inset and buttons had outset borders.
yeah i can mark a field as numeric... but then when a phone renders the number only input all popular keyboards will also leave out every single clipboard buttons and helpers. url where you can also search if you type a phrase? too bad you just lost all typing correcting and prediction. it's lame and hopeless.
[1] https://stackoverflow.com/questions/5328883/how-do-i-style-t...
Annoyingly, Chrome used to allow styling of validation-messages using vendor-prefixed pseudoelement selectors, but they removed that functionality and never brought it back; I'll chuck this on the same pile as other arbitrary annoyances like "can we have a native HTML combo-box please" and "why is <select multiple> still a horribly unusable ctrl+click box instead of a checkbox-list?".
The problem is that it's quite tricky to correctly subscribe to the changes of this validity state. There are indeed some validity events being dispatched, but unfortunately not always. Updating form state programmatically (such as calling "form.reset()" or setting input value via "input.value = '...'") doesn't trigger these events.
I think this is a separate good topic for investigations and for suggestions to the web platform
The majority of the work in form validation is not in the validation of the data, but in the UX and interaction, display and update of state. There's no generic way to handle it, as it's very dependent on the app itself.
Keeping the browser smaller and cleaner, with less logic seems to be a better idea.
Said no designer ever.
At work our design team came up with buttons that are 10x10 pixels on my screen. They are used to change pages (like on mobile, but this is a desktop program), the scroll events are ignored by design, so you either click the tiny buttons (which are slightly darker gray than the dark background) or you simulate a finger swipe via drag and drop with the mouse. Yes they designed a touch GUI for a desktop application.
And this also assumes that the browser validations are in any way usable to begin with. I would argue that they are not, and would require some sane styling to become usable in the first place.
I have never worked for any company or organisation that believed this. Most clients will send you their branding guidelines before sending their feature requests. If they get to choose between adding a new feature, improving usability or making sure everything follows the branding, they will choose the branding every time.
This isn't an issue if everyone's an accessibly expert, otherwise we're sacrificing usability.
People like to complain about JavaScript on websites, but they often don't know in what a bleak world they would live.
"Using specific type attribute values, such as "email", "number", or "url""
These can significantly improve user experience on mobile by triggering the optimal keyboard.
EDIT: which I agree with.
Native HTML validation has many flaws and visual customization is not my biggest concern to be honest (but it's the nail in the coffin).
E.g.:
- It's impossible to show multiple errors at once per field unless you concat strings ("You need a number. You need a symbol. Must be >10 chars.")
This is both bad UX and bad for accessibility (you cannot navigate concatenated strings on the accessibility tree). And this isn't even implementation dependent, it's the spec! You need multiple errors at once because playing whack-a-validation-error is not fun for users.
- It's browser-dependent which is bad because you can't control it and because the implementation is generally terrible (e.g. in Chrome it shows a popup on focus, which is not very accessible by itself because (1) it's a popup (2) that shows modally (3) and can't show all form errors at once).
Not using popups for important information is accessibility 101, but browsers cannot afford to do anything else without interfering with the actual document.
- You still need custom validation for form-wide errors (like errors that don't belong to a particular field, "Fields A and B are incompatible") so you might as well have a consistent validation story.
- It requires you to have hidden inputs to be consistent (-ish) if you have some custom input that doesn't fit any of the native input types -- this breaks accessibility too and fixing it is as hard as having your own accessibility-friendly validation story.
- The custom validity API is imperative and cumbersome to use. Not using custom validity is almost never an option unless you want terrible messages ("This field is invalid")
And many more.
HTML form validation is terrible.
And also why browsers started separting these. It’s a checkbox and radio that should contain a text, not vice versa.
[1] https://a11ysupport.io/tests/html_label_element_implicit
https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectE...
It doesn't work in Firefox for Android.
Recently I was trying to get a refund on Groupon because the company I'd bought a Groupon for was under new management that refused to honor my groupon.
The form had a stipulation "minimum of 15 words". Try as I might, I could not get the form to pass validate until I inspected the HTML.
<input pattern="^(\b\w+\b\s*){15,}$" required>
\w - word characters
\b - word boundaries
\s - white
Literally zero allowance for any sort of punctuation.E.g. the "repeat password" example is actually achievable without "setCustomValidity" by using the "pattern" attribute. For that, you would have to dynamically construct a RegEx out of the value from the first input. I didn't want to make the article too long by comparing the solutions, but the point is, with the "customValidity" you see how much more eloquent and easier to read the validation is. So a nicer API here makes all the difference
The "15 word minimum" constraint would look so much nicer as "value.split(/\s+/).length >= 15".
Frontend validation is only there to be helpful for the user, but if you can style it, or trigger it from the backend on submit, you have to implement your own styling anyway.
We try to use browsers standard features whenever possible. Despite looking into using the built-in validation, it's never been worthwhile. Too many gotchas, and we end up using a library to be able to easily support more complex checks anyway.
Furthermore, using a library opens up, in some cases, the possibility of sharing some of the validation code between front and backend.
In particular this article seems to work around one of the issues with `useLayoutEffect`. Not something that should be done lightly.
https://developer.mozilla.org/en-US/docs/Web/CSS/:user-inval...
If I'm making a wish list I'd also like to point a property at a handler function that accepted a `string` and returned a `string | null` (or at least a `nonempty string | empty string`) rather than using an onchange handler, but it is what it is.
I even remember when people started evangelizing client-side validation in the mid-2000s. Javascript was already a normal tool used in web apps by then, and most web developers would regularly be adding javascript to their apps.
Back then it was a bit of a pita as you had all sorts of gotchas with javascript memory leaks by registering change events on controls. I can't even remember the term now, but you could basically have a circular reference between a closure and a control and so it wouldn't cleanup properly.
Also, modern developers probably can't even begin to imagine how slow javascript was on IE6. A loop of a few 100 iterations could bring it to an unresponsive halt.
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes...
It does not translate with the application but with browsers settings, it doesn’t style or fit any design. It looks differently on different browsers and it is really hard to explain to stakeholders “this is from browser I don’t have control over it”.
Wait, which is it? Does not match any style or design, or is it matching the browser's?
And if your application isn't consistent with the browser and OS settings, shouldn't you fix your application?
I truly believe a nicer API would motivate developers to use it, and if native validations satisfy the product requirement, their styling does become a lesser concern.
But surely styling is still important, but another great topic to write about is the fact that you actually can opt-in to showing native validity errors in a custom way!
I could see a case, if a user decides to somehow make a single website use a different language than the others. I guess it would be a browser's job to have specific languages for specific websites.
Explaining to people they should go and change their browser settings is major hassle.
You need to revalidate on the server, no matter what.
These validation at input can be super annoying when you're copy-pasting your strings from other sources, and want to edit them in textbox in-place. Especially if you're on your phone.
I've be frustrated by this on numerous websites, a lot.
Same is true for things like disabled ect https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HT...
> The strings "true" and "false" are invalid values. To set the attribute to false, the attribute should be omitted altogether. Though modern browsers treat any string value as true, you should not rely on that behavior.
in other words required=false may still end up making the field required. FYI.
Maybe that is user friendly but for sure I don't like to see the backend bombarded with API calls each time an user types a letter.
Huge, huge, massive “no no”.
Likewise you still have to do sever side validation as any client side code can be modified, or you can just send payloads directly to the server. IMHO client side form validation is dangerous as it gives a false sense of security.
The total amount of traffic in both direction is pretty small, and the logic is simple, especially compared to lots of other things your server is typically doing.
You'd probably have to wait until the user moves on to the next field, if there's more, but that's also a little silly, as you'd force the user to go back to a previous field.
The problem with vanilla form validations are (1) they're so basic that it's table stakes for any library or framework in this space, even ChatGPT can do it well, (2) there's an enormous amount of other validation scenarios they don't cover, and (3) unless your validation is simple and doesn't require a validation library, now your logic is split between two places.
[1]: https://valibot.dev/guides/comparison/
[2]: https://zod.dev/?id=basic-usage
[3]: https://www.react-hook-form.com/get-started/#SchemaValidatio...
[4]: https://tanstack.com/form/latest/docs/framework/react/quick-...
Can you provide examples of those? Genuinely interested as I'm on a quest of creating a list of recipes that show that native form validation can be just as capable as custom validation libraries
The only downside: the user has to wait 300ms.
I used to think it doubled your workload to do both, but if you are using JS-free client-side validation, I think that the server can just return an HTTP error guilt-free for any invalid input that the browser will catch. It’s a pretty good compromise for format validation.
Indeed the most pleasant UX is to set an additional validation logic on the client side and I don’t think this should the go-to solution.
No, you can handle that on the server too, easily, since you can fill the form with the last known state upon page loading.
You've got tech stacks and cloud services that will put you within 20ms of 99% of your users.
Server side everything is still the safest possible bet you can make.
It is so easy for developers to think they have something better after a simple NPM install, until they test it on a slow (i.e. median) phone or watch a blind person try to use their application and then spend weeks trying to improve things. Given how common web forms are it’d be really nice if we had an Interop-style competition focused on making the out of the box experience better for normal people both for the controls integrated in browsers and the myriad of JavaScript widgets.
^(?=(.*[a-zA-Z]){4,})(?=.*[0-9!#$%]).+$
requires that these characters appear consecutively.Isn't that correct?
I have nothing against regex and the "pattern" attribute is the way to go for many cases, but having this is an alternative is also very nice:
const valid = value.length => 4 && isAlphanumeric(value); return ( <Input value={value} customValidity={valid ? 'at least 4 alpha characters' : ''} /> )
It's gone so far that some peole claim React (and probably other frameworks too) is "a language"; they apparently don't even know it's just a JavaScript library.
But dont remenber to also verify serverside. Anything clientside can have been fumbeled with. (Also kinda anoying to have to duplicate this tho)
Oh yes it is...
I once worked on a project where we had a tool that dynamically built client-side forms based on each customer's needs. After rolling it out for a big customer I discovered (after the original engineer responsible had already been fired for other reasons) that all of our dynamic forms had NO server side validation. none, zilch, nada.
We did have client side validation though, a good amount of it and nearly all of it was using native HTML features, and we had the whole form available server-side as well. So given that I was under a crunch, on form submission I loaded the HTML form server-side, manually iterated over all the elements and re-implemented the validation checks that were embedded in the HTML. Crazy times, but heck it was flexible!
> (Also kinda anoying to have to duplicate this tho)
Security and convenience are like space and time, you can't move one without transformation of the other. <input required={true} />unfortunately you’re sort of back to square one if you want to implement warnings (ie suboptimal inputs but still workable).
Edit: While grasping the ergonomics produces euphoria like solving a complex puzzle it’s also a hint at the pain un-initiated colleagues will feel when tasked with maintaining the code.
The browser is programmable; at this point they should stop getting clever about adding built-in functionality and instead just expose better ways to use the browser as a dumb UI toolkit.
A spinner control, that is.
Spinners always puzzled me, to be honest. There is obviously a need for a compact numeric input control that both displays the exact value and allows rough changes using the mouse. Witness knobs in DAWs—which don’t actually work the way you’d expect from their appearance, you’re supposed to grab and then drag in a linear fashion, possibly ending outside the knob’s screen bounds. Or consider the weird input thing Darktable uses—which at least doesn’t mislead you with false skeuomorphism, but takes a bit to figure out. Then there are the inputs used for color grading in DaVinci Resolve. And so on. And all of them are nonobvious. Spinners are obvious, but they are also needlessly fiddly to use with the mouse, and neither do they provide the at-a-glance readability of knobs et al.
I feel like humanity just hasn’t solved compact numeric inputs yet.
I rarely want those arrow buttons for numbers
It should be split into:
type=integer so the keyboard does not allow anything besides 0-9
type=decimal so the keyboard also allows decimal dot/comma and a fixed number of decimals!
type=float which allows for scientific notation, e.g. 1.2e42
> Browsers automatically provide validation to ensure that only text that matches the standard format for Internet email addresses is entered into the input box. Browsers use an algorithm equivalent to the following regular expression:
> /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
Which doesn't even allow all valid email addresses :|
No support for quoted local parts. No support for punycode domains. Disappointing.
Use <input type="text" inputmode="email"> instead to just get the email-optimized keyboard on phones without the misguided validation.
In most cases, GDS now use just 3 text fields for day, month and year, but recommend pickers for dates close to today's date e.g. for booking an appointment, because a picker is easier if you don't know the exact date without reference to a calendar.
Sadly they don't currently have a recommended picker, but there's a useful discussion of what has been tried here:
https://github.com/alphagov/govuk-design-system/discussions/...
I'm trying to picture a room full of <s>people</s> developers agreeing letters are numbers too!
Lets give the little people a slider but lets call it a range!
I really feel like they are trolling.
You start with a neat database table then you engage in an endless struggle trying to allow the user to edit a single row of it. It really feels like you are not suppose to do it. As if it was intended to be as annoying as possible.
E.g. any leading zeros get dropped out of phone number starting with a 0, very common.
And that means it's barely doable with normal inputs, the special ones support even less events.
There's your problem right there. Can you expand on the reasons? It seems like very bad practice for a website to provide it's own "keyboard" instead of using the system keyboard.
The fact that something provided by the browser can fail accessibility requirements is definitely ironic. We're always taught that the motivation to "use the platform" and "follow semantics and semantic elements" is partly to satisfy the accessibility concerns.
I still think it's worth to leverage the native validation mechanisms.
* You don't have to use the native validity tooltips for the error messages. You can read directly from the input's ValidityState (input.validity) and render the message however you like and show multiple errors if you need to
* The browser can improve and you will benefit from using a standardized approach
The fact that "not using popups" supposedly breaks a11y sounds weird, though. But if you need to respond to an audit then this is the way you can go.
> Errors that do not belong to a particular field
These are indeed interesting! There are techniques to handle those, too. In my project I have a "HiddenValidationInput" component that renders an invisible readonly input that serves the purpose of rendering a custom error that doesn't belong to any other field. It's in fact quite a pleasure to use because you can just conditionally render it.
> The custom validity API is imperative and cumbersome to use
Absolutely agree on this one, and handling this is exactly what my article is about. And I really hope that this part will improve in time, too
Feels like I don't gain much from that. Native validation is very limited and the few cases that it covers are super simple to implement already. Am I missing something?
I'd rather have a `validateSomething` which returns a discriminated union of error causes than using `pattern` and just getting a boolean.
> In my project I have a "HiddenValidationInput" component
Yeah, that's an accessibility issue (and the UX for the common user is terrible too for multiple reasons).
> it's the spec
This one? https://html.spec.whatwg.org/multipage/dom.html#concept-elem...
I don't see anything that defines how validation messages should be presented (not even that they should be present)
We didn't discuss browser-specific issues in detail, but I edited some points in my original message that highlight some of the issues that I suspect make it a no-go for accessibility.
The more websites use this, the more pressure Mozilla will feel to fix their browser. This isn't something like WebMIDI or whatever API Chrome or Safari implemented before standardising, it's part of the original HTML5 spec.
https://gs.statcounter.com/browser-market-share/mobile/japan
That's still not a lot, but above 1% is a decent threshold to decide to support a browser.
even re-fetch them from the server on each input change in the client
or just ditch the whole thing and do it in htmx :->
To take an extreme example, you could ensure that validation happens identically on both the back and front end by writing your own framework with that property. You could create a framework with no more security bugs than the next best alternative and while providing great UX. But writing a framework and shaking out the bugs is a huge lift.
So in practice you can't go all the way out on the third axis and it is approximately a dilemma. But if you're on the lookout for exceptions you may find an opportunity to cheat/curve bend (eg as suggested by other commenters, when using JS for the front and backend, you can use data modeling libraries like Zod to get most of the benefit for a fraction of the price of writing a framework).
I was once discussing a third-party integration with a React developer. The integration required that our app POST a couple of fields to the third-party's site. I found that the developer was struggling with the integration and they were asking me questions about it when I said something to them along the lines of "It's just an HTML form, with a couple of hidden inputs that when submitted make a POST request to this URL" they said to me "Yeah, well HTML is kinda old, it's not really used anymore"...
I'm sure I've said plenty of stupid things when I was green but I hope no one remembers them like I remember this one. It lives rent free in my head.
In my personal experience, react allowed me to rely more on the native web platform APIs, not less, than other frameworks (at the time that I switched to react)
> I'm sure I've said plenty of stupid things when I was green but I hope no one remembers them like I remember this one. It lives rent free in my head.
I'm doing gigging while my product is gaining traction. Last week, I received this verbatim rejection for a PR review at a client, who's oldest developer is 27:
"No, we don't want all the logic in the same place. You must split the logic up"
This is also one that will take up valuable space in my head till the end of time :-(
(PS. Yes, I split the logic so that it was evenly balanced in 3 different programming languages, instead of having the entire logic in C# alone)
I don't think I understand how it would be "worse" for plain JS and HTML though. Would love to hear your thoughts.
Actually, there is one possible concern. When HTML is returned by the server includes inputs with set "custom-validity" attributes and this HTML gets open by a browser with no javascript enabled, this would make the input "stuck" in an invalid state. This is an important edge case to consider but I do believe there is a resolution that would satisfy everyone
The concepts are obviously easily translated to other component frameworks, but they also do apply to pure HTML and vanilla javascript.
The problem I am highlighting in the article is the absence of a declarative nature to the Custom Validity API, so I think it makes sense to use a declarative component approach in code examples
The browser should provide low-level capabilities and let developers build the high-level functionality from it.
This article ultimately supports this by showing us exactly how half-baked this particular browser feature happens to be.
But firstly, I would consider what you're missing when you abandon native validation
* On submit, the first field that needs attention gets focused automatically
* Error messages for semantic attributes are localized automatically by the browser
* The native message tooltip are actually nice and their placement is handled by the browser. They aren't the best fit for any design system, but for many products they are way nicer than custom implementations.
* Possible styling using CSS pseudo-classes such an ":invalid" or ":user-invalid"
In the end, I do think that the developers would benefit from a more explicitly exposed API for this. Just like we got the "new URL()" constructor, but earlier we had to create an anchor node, fill in its "href" attribute and then read the anchor properties to get to the parts of the parsed URL.
That is long solved.
> Error messages for semantic attributes are localized automatically by the browser
Assuming I want to use their error messages. I would prefer to provide my own, more detailed, error messages. Also what good is localized error messages in a non-localized form?
> The native message tooltip are actually nice and their placement is handled by the browser.
I definitely don't like the placement of the tooltip nor do I even like using tooltips for showing error messages. I much prefer permanently keeping the error message displayed under the field until the user edits the field.
I make some pretty large forms in my job with a lot of complex validation rules and non-technical users. We do validation way better than this.
(Consider Triptych [https://github.com/alexpetros/triptych] as the baseline for what browsers should have been providing since 2005 or so.)
Adding more high-level UI functionality is really in conflict with the idea of browser as platform. Other features, like WASM, are pushing the browser the other way.
That idea died sometime around 15 years ago.
Chromium can probably be best-described as a kind-of user-mode OS at this point.
Absolutely true! But I like to do it because I personally think it reads more nicely and is more explicit and that's what I do in all my projects. But it is indeed a matter of taste and I have nothing against code that follows the convention to omit the "true" value.
Every time I've asked a marketing person about this they get hand-wavy about "it all comes out in the wash". But meanwhile they say things like "our analytics show that our market is mostly older and non-tech-savvy people". I'm not sure that the analytics numbers do actually show that. I think that's just the demographic that you can see.
custom-validity={value.length ? "Fill out this field" : ""}
you can only use a static string for an attribute. So you'd need an event handler to set custom-validity from javascript when the input value changes, then a handler to setCustomValidity when custom-validity changes.In other words, it's the same exact imperitive interface as setCustomValidity, except with an extra layer and the extra event handling has to be implmented along with it.
If I had a say, I'd go for an interface where custom-validation would take a javascript function name, and that function would take the value as input and optionally return a string with a validity message. Or it takes a javascript snippet like onclick, except one which returns an optional string value. Then again, there wouldn't be much difference from onchange.
Edit: to counterbalance some of the criticism, I think the article is very nicely written and formatted, and the interactive components are a good touch.
htmx looks dope af thanks
Yeah, rightly so. It's reluctant to be what it shouldn't be.
The issue here is, at what point does usability take precedence. Does input validation fall under "branding" or "function"? IMO, an error modal is nothing to do with company branding, etc. — it's not even part of your document, it's the browser's responsibility. The browser can decide to do something completely different from showing a modal as far as its concerned, so you shouldn't make any assumptions. Your responsibility ends at declaring what valid data is.
Having as little native anything means you go from n sets of documentation to 1.
You give the same error messages based on whatever custom validation and control the output.
Using the related pseudo classes :valid, :invalid, :required, :optional is nice, but until last year you still had to do custom logic there because :user-valid/:user-invalid weren't implemented outside of Firefox. That created additional work and was annoying.
If field validation is "standard HTML" and browsers can't do it in an accessible way, that's squarely a browser problem.
I'll quote my top-level comment:
> This is both bad UX and bad for accessibility (you cannot navigate concatenated strings on the accessibility tree). And this isn't even implementation dependent, it's the spec!
> Not using popups for important information is accessibility 101, but browsers cannot afford to do anything else without interfering with the actual document.
Plus it doesn't matter who's to blame: people with accessibility issues need access now.
Because browser makers are merrily taking that free pass, whether we like it or not, and people who need accessibility allowances need them now, or better still quite some years ago, rather than at some future time after we've nagged the browsers into taking useful action.
It isn't entirely the browser people's fault, there are significant issues in the spec, as already discussed in these comments by people who know more about it than I, and that is part of why they feel justified in taking the free ride, but as some of them were involved in the original specs and they are in a position to propose alternatives & deliver PoC implementations, it is more their responsibility than they think. After all, Google in particular are more than willing & able to invent new specs¹ and throw implementations into production, when there might be marketshare, stalk^H^H^H^H^Hadvertising income, or protection money² on the line.
----
[1] and Apple deliberately break them, old or new, in a fit of pique!
[2] Nice app/extension you have there, it would be a shame if it started failing store inclusion reviews, or if APIs had breaking changes for our benefit underneath you.
I wish there were more lightweight websites, none spring to mind other than HackerNews, SourceHut, and Pinboard.
But for any more complex form with dynamic content, JS is still inevitable. I guess for HN the input form at the bottom is enough. But Algolia uses a custom input component already.
Zero JavaScript is rarely practical when there's meant to be interactivity of any kind. The issue isn't the language, but the appalling bloat that is now the norm on the web. And, course, bad design in its various forms.
And I think you're wrong.
Consistency with industry standards is a lot more consistency than consistency just within one silly "app" webpage.
Email is older than absolute majority of active developers and yet, it seems, simple knowledge like "what is email address" remains such an arcane knowledge that you are being looked at weird when present something a tiny little bit more correct than the status quo.
Where else can we assume that the common knowledge is flat out wrong?
Anything you can send an email to that is received, as far as I am concerned. I have my own domain, so why ahould I be forced to add an arbitrarily long string to it to be able to receive the mail? Or exclude <site>@myDomain.com from being input on <site>?
Or the worst of the worst: Disallow all but a few domains for emails.
At this point, not validating it cient side at all is IMO the correct approach, and instead send a verification email.
100% this.
The only acceptable hard validation is to check whether there is an @ between some characters. something like `.@.` in regex.
It makes sense to do sanity checking (soft validation) on client side. There is 99.9% chance that `muppet@gmial.com` is wrong, outright rejecting that is wrong, though.
Really? I tested with a punycode domain on regex101 and it worked fine, do you mean that it only works with ones already converted to punycode?
I think that a quick improvement would be to let the mouse wheel "spin" the number up/down when the input element is focused.
An even better improvement would be having the `<input type='range'>` element actually display the value as it changed, and allow the user to set that value directly (say, by typing it in).
Right now, range is useless because the user cannot tell what is selected. The developer has to add in extra JS magic to let the user set range to an exact value, or to show the user the value they have chosen.
If `range` is improved in this way, then spinners are redundant and can be ignored.
Firefox did that for number inputs for a long time, until very recently. They switched it off in Firefox 130 because people kept inadvertently changing values in forms while scrolling through them [0]. Personally, I've set the about:config option to reenable it since I've found it useful in certain interfaces, though I can't imagine it's much longer for this world.
I guess the room for unwanted consequences is a bit bigger when the scrolling controlls the value instead of just the viewport.
> (NB: I'm deliberately not saying complexity, because the code doesn't necessarily get more complex)
the context was already lamenting the duplication of code, which in itself is a form of inconvenience, as you kinda admit; because generalizing it to "complexity" would be forgetting the possibility of adding resilience, and adding stuff doesn't necessarily mean anything gets more complex - just more entrophic, the stuff added may not be optimal. > But writing a .... is a huge lift.
And also the only way to minimize the security risk; by rewriting/auditing/formalizing.Ultimately the risk transformation is exponential; don't roll your own crypto, don't DIY authentication/authorization, don't risk your own inconvenience and assume security.
However the opposite, to use all the "agreed"-upon code, introduces a near similar surface area of risk, simply spread across more vectors. And because the vectors are spread, and the system is more complex, the dissolution of responsibility leads to the opportune laziest option - patching code together, trusting it works.
it would be wise to question why this convention is so normalized.
Your point about trusting conventional code is well made and important. Once I repeated that I shouldn't roll my own crypto. A cryptographer shrugged and told me, I mean, somebody has to write it, and that person might be you. (That person isn't me. I don't roll my own crypto. I do roll my own auth, because I'm comfortable with my understanding of authn/authz attacks. Use my software at your peril.)
Regarding complexity what I was thinking is that, after a lot of clever reflection, you might realize the proper solution is actually to take something away. To give an illustrative though not very realistic example, you might realize you didn't actually need a web backend at all and that the app can function local-only. Thereby solving your UX and security issues - client side validation is now completely acceptable. This architecture is simpler (less complex) in that the diagram contains fewer elements, but more sophisticated in that it contains more baked-in wisdom about how your normally web-based application can fulfill all it's requirements locally.
>To give an illustrative though not very realistic example, you might realize you didn't actually need a web backend at all and that the app can function local-only.
ssshhhh, don't give away the only secret that keeps us employed.if they knew for certain our stuff wouldn't break, we wouldn't had been kept around.
>but more sophisticated in that it contains more baked-in wisdom
you can't beat Shannon's limit, or the 2nd law of thermodynamics, no matter how much you allow "sophistication" or "wisdom" to do the lifting.It's hard to impossible to properly guide OS outside the browser regarding what keyboard we want at different points in time unless we end up also implementing custom keyboard plus some way to talk with it from JS. Previously we used a Chromium extension that could bypass some of the issues because it had privileged access and thus could send "secure" events.
EDIT: For some extra context - for reasons of ease of use, we want the keyboard of appropriate type (numeric, qwerty, other specialized layouts) to show in position related to actual input field, not take entire lower part of the screen like typical on-screen keyboards. For dealing with possible edge cases or otherwise making it more accessible, we also provide for the keyboard to be draggable by user.
[1] Sometimes it's accessed externally instead of in-person, for various reasons this means we have both the ability to open the web interface and use VNC.
[2] By big I mean we have a complete PC running Linux there, with intel CPU/GPU and an SSD
2. "Solved by host environment" in practice means "worse user experience" as pretty much all of them simply use lower portion of the screen.
In comparison, the current draggable on screen keyboard I spent significant amount of time getting working allows the worker to drag the keyboard around if it overlaps a piece of information they need, as well as takes comparatively little space on screen enabling workers to better see what they are manipulating.
And I have this opinion because I had to deal before with format configuration and normalization before saving to the database, when using a JS library. Now I just drop a "input type=date", and I know I'm going to get the ISO formatted date at the backend.
I always keep my OS and browser in English (makes searching for error messages sooo much easier) but I hate that I need to change my OS settings just to get Firefox to display the date in a proper way on some site.
My apps usually deal with non-technical people (thus ISO in the browser input is out of the question), and sometimes spread at least between Europe and US (so people would enter MMDDYYYY and DDMMYYYY, and keep in mind that some dates work validate for both formats, namely every 12 first days for each month). Behind the scenes everything is ISO and UTC, but everyone gets their preferred format in the frontend.
I'm not getting your Dutch example. If I'm in the US and use MMDDYYYY almost always, and want to access some Dutch site, what date format would you show me in the input form? DDMMYYYY only because the backend is hosted in Europe? You will get wrong dates (e.g. 11/1/2024 for the first day of november, your system will store 11th of january) for at least half the US visitors.
Or maybe you are talking about "dates displayed" instead of "dates input", which is a different problem?
Nothing my front-end people could possibly do would trick me into trusting user input.
but also cross-system context switches, amateur RegExp, escape character (ab|mis)use, etc. can make "user-input" propagate farther than any one team's boundaries.
assertions/test coverage/fuzzing at every boundary so user-input taint analysis can't fail is a requirement for a system that passes user data around more than one time or tech stack.
How so? The backend ALWAYS validates. No communication necessary, whether or not the frontend also validates doesn't matter to the backend. Frontend validation is to improve user experience, nothing more.
and to reduce server load.
>The backend ALWAYS validates.
Exactly. Sometimes in a system so big compartmentalization is required yet meta-communication is inhibited, that comfort-ability can lead to false asserts / assumptions."We always validate - no need for _me_ to do it" type bystander effect / diffusion of responsibility.
The problem with having separate client-side and server-side validation logic is that you (generally) want the rules to be the same, but you end up needing to write them twice, usually in completely different technologies. I have seen many, many cases where the client-side validation and server-side validation got out of sync, and then just like you put it, obscure bugs or security exploits can arise from this.
In general, I think client-side validation should really only be used for the basics, often with respect to type (e.g. the email/URL examples given) and just basic "required" (non-empty) fields. Anything more complicated than that should be done solely server-side in my opinion - e.g. I wouldn't use setCustomValidity with a complex set of client-side rules. What I think is important, though, is to ensure that if the server validation fails that the error message that comes back is not just a single "Bad input!" message, but errors can be keyed by field to ensure you can display field-specific error messages and error highlighting.
Another option I considered back in the day when my backend was on NodeJS is to have the server return the text for a JavaScript validation function before the form itself is actually rendered. This, this function can be run client-side for immediate feedback when the user submits the form, but it's also the exact same logic that is run on the server when the form values are received.
The `<input type=datetime-local>` on FF has a broken time-picker[1], has always been broken, and there are no plans to ever fix it, ever.
[1] In that it will let you pick a date, but not a time - the time must be manually typed into the input!
That you’re correctly using html forms won’t quickly lead to browser improvements.. so the result is that users will hate your forms. Users/your customer might possibly even think that you’re to blame, and not $browserVendor.
But then it turns out that you really do want a free-form text input. Let people paste text in, edit their text freely, then let it validate afterwards. When it validates, then reformat it.
For example, text boxes with length limits. These are awful. It messes with your ability to paste something in, then edit it down to the correct length.
> In step (3) here, if you do several mousewheel-spins while also subtly moving the mouse (just from placing your hand on it), it's quite easy/possible for the first spin to inadvertently change the value that you just entered (since step 1 had left the cursor hovering the input field, so that's where it starts), and then for the subsequent mousewheel-spins to successfully scroll the page. This can mean you change the number you just entered without noticing (and also without it being "in the middle of an existing scroll action", hence my note that this suggested mitigation wouldn't necessarily help).
The cause being that people don't look at where their cursor is before they start scrolling, and don't look at the value since they've finished entering it.
The correct context model is to not select an element for scrolling until it has been made the active element, and that UI element SHOULD have some sort of embellishment to make it obvious that's the focus.
You can validate roughly anywhere, but at the absolute earliest, only re-format on blur. Never earlier. You have no idea what the user might be doing in the meantime.
And even then, I'd strongly suggest not changing what they entered. Change it to a display-only element with nice formatting if you want, but don't screw with their input.
- pasting from Word
- QA testers being through
- devs pranking each other
The third one is by far the most common. Word is much better these days and I've not seen that happen in a long time. I wish I saw QA test this stuff more often. The idea that it's common enough that you'd break your UX to handle it baffling to me.
For example phone numbers can be a string of digits, or multiple strings separated by spaces or hyphens or with parts enclosed by () etc
It's a more pleasant UX to let them paste anything, then edit it inside the input, validate and submit.
What I have found to work well is when the user unfocuses the input field or on submit strip everything but expected values then validate. If you want you can format the value at this time too (and the formatting won't interfere with text input).
If you want to get really fancy you can strip and format as they type and be careful to keep the formatting "virtual" such that the user is only editing the raw digits but this is very tricky to get right on all platforms and support all expected native editing UX. But even in the best cases this can have bad edge cases. For example the user pastes some text but it happens to have multiple numbers in it, if you eagerly strip and format what is left for the user will be these two numbers mushed together with misplaced separators or similar. If you let them paste, remove the unintended stuff, then format on blur this just works and is understandable.
You could remove the zero-width spaces in validation (for eg a phone number).
If I ever grew to hate users this much, I would find a new career. You should consider that.
Which is really nice for copy pasting. For example, I have a number with spaces in it, and when I paste I get nothing or only until the first space because someone decided I'm not allowed to have non-numericals in the input field at anytime.
And final validation needs to happen on the server side anyway - anything before that is just a usability helper.
Any designer unwilling to say this, especially in the context of accessibility, should be outright fired. They are bad at their job.
Accessibility is a legally mandated requirement, not an afterthought
The place where I live is very good at pretending to do the right thing while doing absolutely nothing.
For example a touristic social account managed by some government entity posted some extra complicated wheelchair lift (that will inevitably break in 1 month at most) to show how disabled people are well integrated.
Meanwhile of course the real situation is that people on wheelchair can go almost nowhere at all. Newer public transport has even worse accessibility than before, elevators are mostly broken at all times and regular ramps are missing, doors regularly have super strong springs and a button to open them (which breaks all the time) when they should just have a much weaker spring instead.
Designers I've worked with are like the tourist social media account. Showing the one single place they made accessible and explicitly saying in meetings "we are good people, we care for disabled people"… and then hating me for pointing out the million other things that are not accessible.
Of course they love to show off how good they are to the poor disabled people, but that doesn't mean anything until some government reminds us that we are in breach of contract unless we make our GUI accessible.
The second group does make things that look nicer, but the first ensures it can be used. You really want both, but then you need to be careful about who wins when they disagree.
Which everyone is only doing because it's an industry fad likely stemming from copycatting one or two instances where it was done for legitimate reasons.
And I would argue that the value the user receives from that top 10% of sites is not commensurate with the pain the user receives from the sites that think they're in the top 10% but aren't.
What percentage of websites are rolling their own functionality instead of using any one of the various library and framework that do this better?
There is no way that every single browser is going to implement some high-level feature in a satisfactory and future-proof. It's the wrong place to do it. Almost every attempt has been at least a partial failure. We might get something maybe a decade after it's in common use and then only the most basic version of that. And we get browser bloat for our troubles too.
I don't use the standard <select> controls in apps anymore because the build-in version is too simplistic. Don't even get me started on file uploads. Is everyone just supposed to be held-back by the minimum a browser can do everywhere? Why waste browser developers time building things that no one really wants to use.
1: https://en.wikipedia.org/wiki/Principle_of_least_astonishmen...
"satisfactory" is exactly what browsers tend to provide, with a side order of "no surprises". Designers reinvent browser functionality on a theory of "I don't want satisfactory, I want delightful and unique", and sometimes they succeed, but often they fail. As a user, I very rarely want "unique" when it comes to design.
You don't have to be held back by browsers, and you may well be able to do better, but many people who think they can do better end up doing worse.
> There is no way that every single browser is going to implement some high-level feature in a satisfactory and future-proof. It's the wrong place to do it.
There are far more websites than web browsers, and the turnover at the typical web agency is very high. There is no way that every single web dev is going to implement form validation in an accessible, secure, and his-webdev-replacement-proof way across all browsers and devices.In a way, yes. I do think there's a lot to improve from the browsers' side. I guess what I'm trying to say is that the "half baked" solution is also not quite as bad as "no solution" and 1) it can be improved, 2) it really can be used today if you know "how to cook it right"
If you code for Windows or Mac OS, you get standard controls, and they do come with a lot of functionality, but ultimately it's still just building blocks for you to build your own functionality. That's what browsers should provide -- low level building blocks.
“This site only uses functionality provided by the HTML spec” is not a useful goal in and of itself. Using the right tool for the job, which might be JavaScript, is always more important.
On flipside, note that many regulations - in any human domain - are oriented to raise the level of the worst performing, not to support the efforts of the best or to optimise the middle.
Also I'm disabled myself, although not in a way that requires any adaptation to use a computer. But I of course notice these things a bit more than average; and I get to hear my elderly father's complaints about software that he can't use because of inaccessible design.
Of course a designer should be qualified and notice these things even more… but all they do is move buttons around and disable copy paste so that even fully abled people have a hard time using our software between versions.
- Date display. I prefer to show it in the browser preferred format, but in the end what you say is also OK. It's a very minor issue.
- Date input. I would never force a format to the user, it there is any chance people from different locales can access the web. The correct way, IMO, is "input in the preferred browser format, send data as ISO". Any other combination would cause errors, e.g. "input in the preferred browser format, send data in that format" and you'll get wrong dates in the backend, or need to do a lot of gymnastics to avoid them. "input in server locale, send data in any format", and you'll get wrong dates from people used to any format that is not your server locale that happens to validate in multiple locales. "input in ISO, data send as ISO", you'll get users upset because "YYYY-MM-DD is stupid, use MY locale instead".
I'm in agreement with showing/inputting dates in the users' regional setting.
If you built an app that used just what the browser gives you and nothing more, you're leaving so much functionality on the floor. Having more expressive power often makes things simpler -- using more complex UI controls has allowed me to eliminate whole pages from my application. Users are happier and more productive.
Browser UI implementations can't do one thing that is vital: compete.
Yeah, please do. Because 99.72% of that "functionality" is used to implement crappy ugly bullshit.
That ship has sailed. (and I wish it had not)
> Everyone's site looks and feels inconsistent with every other site.
Somehow, this model won. Most people muddle through and figure it all out...
UX/UI is solved just use spreadsheet grid, you can do everything in spreadsheet and you will have exactly the same interface/way of doing things.
It is not a joke - I personally have like 80% of things in a spreadsheet (don't get me started what kind of spreadsheet abuse I have seen in my career). But I do understand that lots of stuff can be done much more efficiently with tailored controls and not everything is couple of drop-downs/text boxes.
To be fair, it's not usually that frequent. Just a funny coincidence that I've JUST dealt with it more recently.
<input type="text" pattern="[0-9.-]*">
though?
How is that more pleasant than a textbox which automatically removes the extra characters?
The nice thing about the native input is that it is very simple, predictable and flexible. It may be easier to make a better UX on the happy cases but it is very difficult to not add some suboptimal and confusing UX on the less happy cases. Often times it is best just to keep it simple so that the user can easily complete their task rather than adding some "magic" which may backfire and confuse users.
It is surprisingly often that I need to open a text-editor or clipboard-editor to format values before pasting them into apps or websites because they have broken an input field by trying to be magic and failing to consider anything but the happy cases and maybe one or two bad paths.
FWIW if you're copying text on Android, you can tap the clipboard popup to edit the clipboard item before pasting it elsewhere.
Instead of asserting that "users are too stupid" as you have done earlier, perhaps programmers should be less stupid and write more permissive parsers.
Accessible design is actually pretty hard, and most designers and programmers get this wrong. If you want some good design advice, you can start here: https://adamsilver.io/blog/the-problem-with-live-validation-...
To clarify, we get _asked_ by our users to implement fields that limit input to help them avoid mistakes. Our QA and UX teams agree. This isn't a unilateral engineering decision.
This article already starts out with how many ways you can screw up this built in browser feature. I bet you didn't even notice that the article examples were slightly broken. The "fix" shows the error when you press submit but doesn't highlight the field in red like if you backspaced it to empty. This is something my validation code does automatically and correctly.
And this is why you fail. When you use components built into the browser, everyone gets to benefit from the same years of experience and testing, so that edge cases you have never thought about are handled correctly. Websites that re-implement text boxes, history, scrolling, so many things, never get every detail right. They always break on cases the built-in equivalent would handle correctly. Sometimes weird edge-cases, but pretty often completely normal cases that don't appear on the developer's development machine.
As browsers continue to give developers more low-level control, the less of a problem this is. Take one of your examples, history. This used to be a high-level feature implemented only by the browser and if you built an SPA your users either had a very bad experience or you had get "clever" with various tricks. Now, we have a nice history API.
You say that everyone benefits from the same years of experience and testing but at the same time they're limited to a single vendor. A single idea of how it should work. And a single implementation. Right now if I don't like how validation works/looks that is implemented in JavaScript, I can choose any number of alternatives or implement my own ideas.
The browser should help developers build the best possible solutions, it should not implement those solutions itself.
Browsers themselves have always had weird edge-cases and as a web developer I've always had to work around them (see this article). Sometimes even depending on the browser. The whole idea of an "SPA" was never even imagined by browser makers but developers made that happen.
That's why I was suggesting letting the user paste in these 'wrong' characters, but offering help in removing them.
Of course, that's a trade-off. And it's more annoying to design and implement than just forbidding those characters from entering the input field in the first place.
I never noticed that after 13 years of Android. I checked that now and I could not find a way to do it. Samsung's keyboard has a way to look at the clipboard but I could not edit them. Swiftkey does not. Maybe Google's keyboard? It's not on my phone. I looked at a couple of videos but they don't look anywhere like my phone. Not a feature to invest much time on it. If I have to edit the clipboard and I can't do it where I want to paste it, I open an editor and paste it there.
Quite the opposite, in my experience! As browsers give developers more low-level control, they're more tempted to build half-assed replacements for built-in functionality.
The history API - it's good it exists, mainly because it gives SPA developers a way to solve one of the many intrinsic flaws in the SPA design. On the other hand, it's subject to ridiculous kinds of abuse (stuffing history to make it appear to users that the back button doesn't work), or getting out of sync (because web developers can't manage a stack) and making history unusable.
> The whole idea of an "SPA" was never even imagined by browser makers but developers made that happen.
Yes, with generally terrible results, which could have been avoided if browsers hadn't stagnated.
Really? This is like complaining about movies that use CGI -- you only complain when you can see it. When it's seamless, and often it is, you don't even notice or care.
Why stop at browser apps? All apps are terrible on all operating systems for all the same reasons.
This line of argument seems pretty subjective.