Last time I checked, web-browsers today still do not allow you to style the appearance of built-in HTML validation messages [1]; this wouldn't be so bad if Chrome (and Firefox) still conformed to their OS platform UI guidelines (i.e. so it looks system-generated, like how `title=""` tooltips used to be), instead Chrome uses this ugly yellow/orange icon color with black-text on a white background on a bubble with a fixed corner border radius - it clashes horribly with my current project's aesthetics.
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?".
I think the problem here is not as much with the absence of custom styling, because you can quite easily read the native "validity" state of the input and render it however you want.
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
I think form validation should remain an app implemented part of a web form, rather than natively built into the browser.
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.
Checking if a string is a email (or at least looks like one), if it's a number, etc. is such a cheap processing, that setting up and tearing down a connection to the server to process it is a waste of resources. Client side validation has its uses, it's more responsive. The problem is that we want all these custom behaviors when it's actually some rudimentary data input validation.
I never really understood why people want to style stuff like this. I like how you can express yourself by using colors and layout and stuff like that. But at some point usability is more important than branding.
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.
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.
Well the ones I've worked with couldn't care less.
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.
Designers that come from a background of human machine interaction care and will say that. Designers who come from a background of art don't understand what is being talked about and so don't say anything - they tend to only ensure it works on their one devices which they have selected to be the best and ignore everything else.
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.
It is a patronising sentiment, but adjacent tonal cues suggest GGGP is offering it ironically, thus in ridicule of performative compliance.
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.
Yes very patronising, a terrible attitude really. Which is why I criticise it.
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.
I believe that was the commenter's point - that the designers described patronizingly virtue signal about their accessibility priorities, while their other decisions are troublesome.
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.
People want to style things to match their page, exactly because consistency is part of usability. Especially given the limitations of browser form validations, you will absolutely need your own validations in addition to any browser validations you use. But your own validations will look different from the browser-provided ones, at least on some browsers. Which will confuse users, hence decreasing usability.
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 think consistency within an application is far more important than consistency across applications. And even if it were true that users hated the lack of consistency, it would fall on deaf ears: the web page developers can only influence their own page. They can't make Google or Mozilla or Apple come up with an actually usable error model, or any kind of good UI in general, so the only chance they have is to create a good UI for their own page, and hide the horrible defaults that each browser is reinventing.
But at some point usability is more important than branding.
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.
I think you're exaggerating here. I recognise the "branding is more important than usability" approach, but the OP specifically said "at some point". Have you ever worked for a company that forced a design decision knowing it would prevent anyone from using the product? I suspect not; there will always be some point.
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.
It 1000% falls under branding. If you don't make errors consistent across browsers / platforms your support staff will politely but firmly burn your house down. There's no such thing as your responsibility ending and throwing your hands up when you're a company who has to do end-to-end support of your product.
Having as little native anything means you go from
n sets of documentation to 1.
I think the disconnect here is in the interpretation of “more important.” Usability is more important than branding from the point of view of the victims of this kind of over-designed software, the end users. Because they are already being inflicted with a lot of branding, please at least give them conventional error messages.
Sure, but that's not how it works out in practice. It sure looks like everyone just rolls their own. Fun game: can you find any major website that uses the default validation?
This isn't an issue if everyone's an accessibly expert, otherwise we're sacrificing usability.
I love that as well, I hate bloated sites just as the next one here.
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.
On reflection my earlier comment was a little off the mark - all 3 of those sites use JavaScript, but minimally.
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.
I've found it more annoying to mess with the browser validation API and using setCustomValidity/reportValidity etc. than to just use other validation libs. Ideally I'd use whatever library I want and they would call setCustomValidity for me though.
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.
Really? In my experience they easily cover the majority of cases - strings versus numbers, min and max length, upper and lower bounds to values, specifying what decimal level you’ll accept, you can even straight up provide a regex in the ‘pattern’ attribute.
I agree with you 100%; I hate it when websites think they’re being trendy by using undraggably-thin scrollbars or try to subvert the UA’s password-manager (banks…) or naively think they can block users right-clicking or copying images.
To clarify my position: I agree that UAs should be free to show validation messages as-appropriate for the user (I.e. those popover hints) but it is because Google decided to stylise them with a very specific aesthetic/design - as opposed to trying to fit-in to the host system - it clashes more. Now, I’m not suggesting that the UA popovers be fully CSS-able, but I would like to see some kind of coarse-grain control “hint” properties - just like we have with (non-WebKit-prefixed) scrollbars, <button>, most <input> types, and more besides. The issue here is that the validation popovers are almost uniquely exempt from styling compared to all other HTML platform features (the only other exception being `title=“”` tooltips, AFAIK).
By-comparison, this is kinda like the (still) half-broken support for dark-mode: if a page is dark-themed you (probably) don’t want nuclear-flash-white UA-provided popovers stinging your eyes because there’s no validation-popover background color hint. Similarly, supposing my website makes tasteful use of serif typefaces - but the input validation popovers will be in Chrome’s own Material-design sans-serif font, while OS/platform widgets will be in some third other font by-default but can generally still be set via CSS. If you’re on HN then you’re likely bothered by inappropriate mixing of serif and sans-serif typefaces, so I hope you can sympathise.
You're talking about millions of dollars of engineering resources to implement what not only doesn't matter, but is probably actually harmful in comparison to the status quo (however ugly that is). And that's just on the implementation side. Now consider the tens of thousands of downstream developers who are going to suck up more resources from their clients because browser developers offered them a new bauble and some knobs to tweak. All going towards something that shouldn't even exist.
I avoid the use of `type=number` and use `type=text inputmode=numeric` instead. It doesn't come with these arrow buttons which most users don't need anyway for entering numbers. Also the keyboard is better on iOS.
But what's crazy is both of those still don't disallow non-numeric input unless you use JS to reject keystrokes and intercept paste. HTML form validation is so incomplete and limited, every time I look at it I want to scream cause wtf there's so many just totally obvious things we need that don't exist by default and we need to reinvent the wheel. Native date and time inputs are still garbage so every UI framework has to build their own solution.
I used to write those fancy textboxes that reformatted your input as a phone number as you type, and intercept paste, and all that.
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.
Very much this. Live re-structuring runs afoul of tons of things you can't predict.
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.
Nah. Users are too stupid to fix their own inputs in many cases. Seen inputs with zero-width spaces that are invisible which fail validation. User doesn't understand why, complains. Enforcing a character set for certain kinds of inputs is a very good thing.
In 26 years of web dev, mostly as a frontend person, I've only seen zero width spaces in three situations
- 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.
I'll be one of those guys. I see the invisible whitespace from pasting ALL the time. I've literally dealt with user complaints caused by it three times in the last two weeks! (Usually customer issues don't make it to me unless our support team can't figure it out or suspects a bug)
To be fair, it's not usually that frequent. Just a funny coincidence that I've JUST dealt with it more recently.
"Break your UX" is a vast exaggeration. I'm not talking about phone number fields, to be clear. I'm talking about like numeric amounts, with maybe a negative or decimal point. It's literally just [0-9\.-] but that still requires JS to limit inputs to that.
It doesn't prevent the bad input, it only validates it on submission. Therefore it's on the user to fix it, and if it's from a zero-width space, it's literally invisible. Non-technical users will have no idea what to look for to fix it (i.e. use your arrow keys cursor to see at which character the arrow key doesn't shift visually, and there's the ZWSP). It happens way too often.
The problem here is that sometimes users and copy pasting from another document and that comes in arbitrary formatting, not the one enforced by the input element.
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.
> 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.
How is that more pleasant than a textbox which automatically removes the extra characters?
What if I copy something but accidentally get another couple words one of which is a number. For example copying from a chat app and get the date with the message. Then my "Sep 24th 416-555-1234" input which, would have been very easy to fix, becomes 244-165-5512 34. It will take me a few seconds to realize what has happened, identify where the intended phone number starts and remove the accidentally pasted digits.
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.
The exact same problem applies. If I copy "Sep 24 $2412.45" out of a message and you quickly "clean" it to 242 412.45 I may not notice and even if I do it will take a second for me to realize what happened and clean up the value to be the intended amount. If I see the original text in the field it is much more obvious what happened and quicker for me to understand what I need to do to fix it.
> FWIW if you're copying text on Android, you can tap the clipboard popup to edit the clipboard item before pasting it elsewhere.
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.
I'm using stock Android, Pixel 8 Pro. Highlight text then tap "Copy". See a toast in the bottom left. Tap on it (not the X) and a little text editor applet opens up. Here you can edit the text and save it, updating the value in the clipboard. Then using Gboard, it has clipboard history so you can see and paste the specific recent item from the past hour that you want. (Unfortunately it can't be edited after initially copying although you can long press them in the Gboard menu to pin for longer or delete them).
In most cases when you are accepting a numeric value it is best to just strip anything that isn't 0-9 then run validation on just the digits. There are some exceptions like phone numbers which may need + prefixes and similar but you can adjust these rules.
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.
Or, you know, prevent invalid characters from the get-go. Same thing as validation, but done up-front. (But as I said elsewhere, I'm not talking about phone numbers, I'm talking about amounts)
I would like to allow people to copy-and-paste text in, and then edit it. That could be a longer text that has the amount in it (but also some unrelated numbers).
Because this often makes the input feel broken to the user.
Instead of asserting that "users are too stupid" as you have done earlier, perhaps programmers should be less stupid and write more permissive parsers.
I'm not using "stupid" in the derogatory sense. I'm using it as a recognition of the skill/knowledge gap between technical and non-technical users.
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.
Yes, you want to provide guidance, but without getting in the way.
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'm not being user hostile. I'm being cognizant that the skill levels of users is extremely wide, and to best serve everyone from a UX standpoint, it's best to limit the characters accepted in the input. It protects the user, helps them avoid mistakes.
From reading your comments, you're extremely user hostile and I hope to not come across anything you work on because they are the very definition of antipatterns
Please read my other comments. I'm not using "stupid" in the derogatory sense. I'm using it as a recognition of the skill/knowledge gap between technical and non-technical users.
> what's crazy is both of those still don't disallow non-numeric input
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.
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.
> Spinners are obvious, but they are also needlessly fiddly to use with the mouse
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.
> I think that a quick improvement would be to let the mouse wheel "spin" the number up/down when the input element is focused.
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.
Isn't this same issue already solved for other scrollable elements? Scroll should only affect the individual element if the mouse was over that element when you started scrolling.
I guess the room for unwanted consequences is a bit bigger when the scrolling controlls the value instead of just the viewport.
That is how it worked, but people still found it problematic. E.g., from one of the comments on the issue:
> 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.
That's almost correct. I generally agree with hover == focus as a Window Manager level thing, but for document inputs within an application I still prefer required user interaction to set the focus location. E.G. a click, a tab, just move the line forward.
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.
> 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:
It's not the fact that software engineering is broken saddens me as much as the extent.
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.
> Anything you can send an email to that is received, as far as I am concerned.
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.
This is particularly annoying on mobile since on-screen keyboards won't adjust to an email input layout and autocorrect will screw up basically any email address as soon as a "." character triggers autocomplete to commit it's guess.
I found this very extended with "date" input. It seems that every single frontend library has its own date widgets, and lots of them look awful in small screens. You have to add a JS and CSS just for that widget, some depending on jQuery. True, some of them are very configurable, but with the tiny cost of "<input type='date'>" you have a widget that looks decent and native everywhere, probably cover your needs, and you can forget about it forever (e.g. no updates, no CDN).
A lot of those date and time pickers will fail WCAG testing as well.
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:
The native date input is terrible. Not the actual native control, which is usually okay, but the field itself. You can't even format the date! That's the number one reason I always use some datepicker library in combination with a regular text input.
IMO, you (the web developer) should not be formatting the date shown in the input widget. The input should be shown to the client following the system settings, so a US browser would show MMDDYYYY, while an European browser would show DDMMYYYY. And the field is correctly (IMO) normalizing all of them to ISO-8601 (YYYYMMDD) before sending it back.
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.
If my entire application used YYYY-MM-DD everywhere, it can be very confusing for users when the input suddenly uses something else. And often the locale or system settings are incorrect anyway. When I an working on a Dutch site with a Dutch locale and lang settings, then dates should be shown according to the Dutch locale, not according to whatever system of browser locale there is.
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?
To be honest I would expect dates on a Dutch site to be shown in dutch format, just like I expect dates on American sites to be formatted in the US way.
Lets clarify a bit here. There are two different problems:
- 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 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.
I had to recently make sure that we do not use any of the more complex input elements, because we need to drive them from on-screen keyboard that for various reasons is also implemented in-page.
And that means it's barely doable with normal inputs, the special ones support even less events.
> because we need to drive them from on-screen keyboard that for various reasons is also implemented in-page
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.
This is for a closed system that unfortunately sometimes is supposed to be available outside[1] - a touch screen panel UI for (big[2]) embedded system.
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
Isn't this use case already solved by phone browsers? Layouts are controlled via the inputmode attribute. Positioning the keyboard should be something solved by the host environment.
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.
They could improve user experience everywhere if browser vendors wanted. E.g. why doesn't my (desktop) browser auto-complete recently-visited / bookmarked URLs when it sees type=url?
My product just failed an accessibility audit because we are using native HTML form validation and the official recommendation was to implement our own validation layer.
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")
Thanks, that's quite interesting and insightful! Thank you for sharing
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
> You can read directly from the input's ValidityState (input.validity)
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).
Interesting, because for my apps, I implement all those validations. The form wide validation are done on server. Basically I have a bunch of layers of validation that leverages everything. Chrome having a shoddy unaccessible design is Chrome problem, I would file a bug report.
That the browser implementations are generally terrible and wouldn't pass accessibility audits, so all browsers would have to change and then some time to pass for the fixed versions to be widespread.
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.
Seems to me that this says that the browsers have the accessibility problems and that's what should be fixed. Why does every website developer have to work around this while the browsers get a free pass?
If field validation is "standard HTML" and browsers can't do it in an accessible way, that's squarely a browser problem.
Because in reality browsers can't do much. The API and spec are broken as-is.
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.
> Why does every website developer have to work around this while the browsers get a free pass?
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.
In an all honest reply, is that the people that writes these specifications, live disconnected from the reality, they don't use the stuff they specify. That stuff works for very simple things, but then when your forms evolve you realise you will be better off just writing the whole thing yourself.
This. Doing relatively common things like cross-referencing from other fields ("did the user specify a country? If so, we can validate the postcode/zip code they just entered, but if not we'll have to wait until they pick a country") almost immediately require JS to handle, and as soon as you're using JS then it's all just easier to do in code than trying to mess around with validation properties.
Yep. This is great until you need a cross-browser date picker, at which point you need to implement a bunch of stuff yourself. It’s frustrating how primitive HTML forms are, after so many years.
What's hilarious is they do have UI for it in about:config "dom.forms.datetime.timepicker". It makes me so angry that it's not on by default. It works fine!
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.
I’ll go one further and say that the customers are absolutely justified to blame the developer instead of the browser. If a developer knowingly chooses a built-in form control whose common implementations are bad for their users, how are they not at fault for the resulting experience?
“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.
The `required` attribute, which this article is about, is an HTML5 thing and first appeared in browsers in 2010-2011. So sure, not brand spanking new, but the web was already used to write modern apps. There's no good reason for the validation features to be so shabby.
Even 'required' doesn't work properly. Browsers do very odd and inconsistent things when your required field is hidden when submitting. Like in a basic tabbed or multi-step form.
If you have a checkbox with a label, please a "for" attribute to the label so I can disable/enable the checkbox by clicking the label. This is one of my biggest pet peeves, maybe its just me.
I was thinking that it's so weird to talk about using standard HTML validation and then everything is shown with React? If we want to teach people how standard works, we can't assume React as the default.
I addressed this elsewhere in the comment section, but there's not much "react" going on in the article. I do think that JSX is very expressive and the concern I cover mostly involves the declarative "component" model for writing UIs. It's not react-specific.
I believe you could probably do most of that with just css now too. Disabling the default pop up from showing up may be the only thing you need javascript to do.
I'm using Firefox on all of my mobile devices but I can't blame devs for ignoring FF for Android on this one. This is an API every other browser had working 10 years ago, it's on the Firefox team to sort out this mess. The less than a percent of users who don't see the error messages for controls marked in red isn't worth ignoring the standard for.
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.
Firefox for Android has a smaller user base than Samsung Internet and Opera. It's 0.5%. It's a waste of time working on supporting it. Especially considering how little time people put into making sure their sites work for people using accessibility software. I don't think it's worth mentioning in these issues unless you're also ready to talk about UC Browser.
Is that somewhat biased? - I assume the number of people using Firefox has a quite big overlap with people using ad&tracking blockers, which block many statistic sites. (Website operators may log user agent which will be somewhat accurate still)
This is always something I question whenever the analytics numbers come out. I know my adblocker blocks GA, so I'm not going to be included in any GA statistics.
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.
As a daily Firefox on Android user, not catching up on standards is what hurts the most. Most painfully to me, all the WebGL stuff like [1] and some minor annoyances like [2]. Still, having uBlock origin among other extensions is a killer feature.
It's much worse than "doesn't work": the validations work, they just don't show any error. It would be okay if validations just weren't implemented, but this is just absolutely fucked. I discovered this years ago after a long and painful debug session, and I'm quite sure I wasn't the first or last to go through that.
I just realized this having switched to FF on Android fairly recently. Working on an app and saw literally nothing when trying to submit an empty required field. Couldn't imagine what I was missing until I searched. I was stunned. No issue with rolling your own validation but this should work!
You gotta be careful about going overboard with it.
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.
I don't think this is particularly pertinent to HTML validation. This is true of any type of validation. The same rule could have been applied on the server, and then you would have had no hope.
That's actually a good argument for the point I was trying to make. Existing validity attributes such as "pattern" are cool, but not enough.
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".
There’s a reason it’s heavily underused. So many frameworks and libraries provide robust, style-able validation capabilities, some with very sophisticated and extendable functionality. Don’t torture yourself if you don’t have to.
You also have to implement your own validation on the backend anyway. There's always going to be someone trying to fiddle around with your form, either using some weird browser, curl, or some other tool that doesn't have the same form validation built in. You're not going to trust that the client actually did the validation, or did it correctly, so the backend still needs to be able to validate input and show the form, with validation errors, on all fields.
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.
One of the things I dislike about HTML form validation is it starts running from page load. So if e.g. you tie error state formatting to it, the form loads up with a bunch of errors which may be intimidating to the user.
There is the :user-invalid pseudo-class that lets you avoid this to some extent, but it has some inflexibility that may mean it isn't enough, depending on your use case.
There ought to just be a property named something like `defer-validation` that does the right thing. But I'm sure I'm not the first person to suggest it, there's presumably some logistical or technical difficulty.
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.
A bit perplexed by your comment. That wasn't a main reason people started using javascript.
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.
Correct, I meant that client-side validation driven by JS became popular because of UX issues when using pure HTML. There have always been plenty of other reasons to use JS with forms besides validation. But it’s notable because forms and form validation are such common building blocks that if people feel the need to use JS there, it kind of infects everything else around it. IMO, being able to build high quality form experiences without JS is critical to reducing bloat on the web.
JS form validation quite significantly predates HTML form validation. The alternative was server side form validation, for the longest time. HTML form validation was meant to standardise and reduce the need for JS validation, but for UX reasons it hasn't really managed that. And that you'll need JS anyway if you're doing validation specific to your business logic that doesn't fit into the set of rules HTML validation has.
I've never understood why this was chosen as the default experience. Most users don't enjoy having every form element yelling at them for actions they haven't even had a chance to take! You can script around this, but at that point the feature isn't doing much. I'd argue this is the biggest reason you don't see more widespread adoption.
True, but vast majority of websites don't do the right thing. So password managers need to manage a database of form input overrides. I worked at a small company building a password manager and it was a bit of a nightmare, we had to allocate support staff resources to handling reports of website incompatibilities.
I worked for a small company that did. The idea was the password manager lived only on your phone, and you'd connect it to your computer in various ways. Notably including our own hardware, USB nub that connected to the phone app via Bluetooth and acted as a keyboard for the device and the app would instruct it to do the keystrokes to enter your saved credentials. Also a browser extension that the app would connect to over websockets (through our relay servers, DH key exchange to encrypt the connection end to end) and the extension would request the app to send down the credentials on demand. Also we were a very early adopter/implementor of FIDO U2F (security keys). The product kinda hinged on the paranoia of the userbase (which I never aligned with, I trust 1Password and cloud sync'd encrypted vaults for example) so it never really took off. It wasn't "my" product, but I worked on it for a few years, right out of school.
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”.
It does suck, but I think not for the reasons you mention.
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!
And your application should be looking at ... the browser settings.
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.
It works for presenting or selecting initial language. Even that is debatable because some big players don't even care about that and present language based on location.
Explaining to people they should go and change their browser settings is major hassle.
Automatic language selection based on location is an anti-pattern. If I am traveling, I don't suddenly switch my brain to another language. Whoever writes websites like that doesn't properly think about it.
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.
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.
> True, but if there's a communication bug between UX and back-end teams, that can escalate into a false sense of security and then an exploit.
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.
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.
You were being downvoted here, but I think you make a great point.
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.
This was one of the biggest "oh shit" moments I had when learning Remix: I could reuse the same validators across front and backend and they could even be right there in the same file.
It's a UX feature, absolutely, but you can't trigger the browsers validators from the backend, so you'd need to implement your own styling anyway, probably even add a bit more information than the browser can natively handle.
simply adding required is all you need.Not required=true The omission is equal to required=false. No one really write required=true, they just add the attribute `required` only by its self. This is one of the odd quarks about html attrs
> 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.
They've used `required={true}`, not `required="true"`, which is JSX, not HTML. The one with curlies isn't even valid HTML. In the old HTML spec, the correct value, if you wanted to set a value, was to set `required="required"`, but these days the spec is looser since it tries to conform to the web, not the other way around.
Even in jsx its not required to add a boolean value. Unless you are passing in a var as a prop in which case sure. But that didn't look like it was the case in these examples.
> Even in jsx its not required to add a boolean value
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.
You usually create debounced inputs for that. This is similar to the autosuggest and typeahead inputs and comboboxes: sending requests to the server in response to an input change isn't something unusual
It’s a major security/privacy issue, you don’t want to tell world+dog all registered users, especially since that’s typically an email address.
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.
It's not actually all that bad, if you do it asynchronously and in batches (as much as possible).
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.
I don't think the amount of traffic is necessarily the issue. You're validation could be fairly "expensive". Maybe you need to do a lookup in a legacy system, maybe you need to check multiple systems?
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.
Ya'll may want to checkout Valibot¹ or Zod² in conjunction with something like React Hook Forms³ or the more agnostic Tanstack Forms⁴. Really sweet form validation that's concise but as precise as you want it to be.
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.
> there's an enormous amount of other validation scenarios they don't cover
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
And he loses his page state if there is an error. You have to do server-side validation regardless, but client-side validation can be a lot more pleasant for the user.
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.
Using your browser's back navigation from the error page to the form should result in the values still being there unless you are doing something stupid with client-side rendering.
The best solution is to use HTMX (or similar) to hook into your server-side validation so that you only have validation code one place (on the server), but you don't have to wait for complete form submission before finding an error in a field.
I share the wish that there was more effort in the browser space to improve the built-in controls but I would also recommend that people thinking they can easily do better try some real usability and especially accessibility testing. One very nice trait of the standard APIs are that they’re very lightweight and people who build assistive tools like screen readers and Braille displays know about and support them.
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.
It's also easily misused. Take the regular expression validator for passwords on the California DMV website, for example. The website states "Must include at least 4 alpha characters". But the validation pattern
^(?=(.*[a-zA-Z]){4,})(?=.*[0-9!#$%]).+$
requires that these characters appear consecutively.
Yep, and the .* means "0 or more of anything", so it's 4 or more groups that each end with a letter. They can be consecutive or not and a group can be a single letter but doesn't need to be - so whatever the failure was, it wasn't that (or the regex was typo'd here to be correct instead of what was actually on the site).
AFAIK customValidity is not an attribute and you can only use an imperative setCustomValidity API which is terrible cumbersome to use in a declarative framework like React.
One gets the feeling HTML in general is underused, since everything has been done in JavaScript for... How long now, at least over a decade?
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.
> 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!
I think it's a trilemma between security, convenience, and architectural sophistication (NB: I'm deliberately not saying complexity, because the code doesn't necessarily get more complex). It is usually physically possible to find a solution with equal security for a given level of convenience, but it will require an investment of creativity and possibly refactoring to realize. Both of those things are very expensive.
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).
> (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.
Just to put it on the record I am happy to acknowledge that duplication is an inconvenience as well as a security issue.
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.
It's a bit disappointing that articles talking about HTML use JSX/React syntax instead of actual HTML (even more so not actually saying it). Example from the article:
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.
It's definitely true that many developers would benefit a lot from learning more about the basic HTML and the web platform. But I refuse to support the notion that this is somehow React's fault.
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)
> 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.
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)
The confusion in the article is so complete that I'm left wondering whether or not the author is aware that what they are writing is not, in fact, HTML.
Yeah, I am aware! Thank you for the concern :) I did address this in an adjacent comment, but I'll say again that I did contemplate over using JSX or not. Also yes, it may have been a good idea to add a disclaimer for the fact that the code I'm showing is JSX, but honestly there are so many other disclaimers I had in mind, all of them together would make the article twice as long and much more boring
It's exacerbated by the fact that the API they propose to make custom validation more ergonomic works for React, but would be much worse for plain Javascript and HTML.
The API I'm proposing would indeed bring much more benefit when used in a declarative way. That's the point I'm specifically trying to convey in the article.
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
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.
Sorry to disappoint, I did hesitate over this. But JSX is honestly very nice to read and also I didn't want to leave the impression that opting in to native form validation somehow forces you to not use javascript. And combination of javascript + html is, again, very nicely expressed with JSX.
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
once you grasp the ergonomics of setCustomValidity() you can go crazy e.g. pass it a multitude of validation rules per input field.
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.
After reading all this, I think I'd still choose to do it away from the browser built in capabilities. I'd rather have full control over the process and the design than rely on the limited capabilities of browsers.
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.
Couldn't disagree more. Browser features can be much better at handling edge cases: disability, localisation, unusual devices, different input methods, weird screen sizes, etc... rather than hoping every developer does it right, building that in is more efficient and consistent. The common cases should be handled really well by browsers.
I couldn't disagree more; it might be good for disability but for localization, unusual devices, different input methods, weird screen sizes I have never seen that well executed by browsers. I almost always prefer a more full-featured alternative from a standard framework than whatever is lowest-common-denominator feature in a browser -- which also, depending on the browser, may or may not work the same or may or may not even exist.
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.
Browser functionality is typically (handwaving on exact numbers here) better than the worst 80% of sites, on par with the next 10%, and not as good as the top 10%. If you're putting in the effort to build a site in the top 10%, sure, you might not want to be "held back" by the browser. But the vast majority of sites would do better by using what's built into the browser.
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.
I don't know, what browser functionality are we talking about? Even this form validation has to be implemented; I don't think I've ever even seen it in the wild.
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.
As a user, I want common UI controls to look and behave the same way across all web sites. Ideally, across all applications on my OS, but that's also a lost cause. POLA[1]. I can accept if the developer wants to somehow extend an existing control to support something new, but it's so irritating when they just re-implement their own thing entirely because they think their ideas are better than the browser's. Multiply that mentality by every site out there, and you have the web as it is today: Everyone's site looks and feels inconsistent with every other site. And everyone ships a different 500 lines of code, each with different bugs, just to implement a drop-down box.
This is one of these things that sounds perfectly logical -- you want all UI components to look and behave the same across all applications and all websites -- but that is more theoretical than practical.
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.
With this kind of take - why do we need different applications at all?
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.
Form validation, form elements, search... I've seen far too many sites try to reinvent a browser textarea or edit box, and fail at very basic things because they didn't handle anything they didn't personally think of. (Some common examples: some of the keyboard controls, or correct handling of scrolling when having enough text in the box to scroll, or the interaction between textarea scrolling and page scrolling...)
"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.
I don't see what difference it makes whether you use some component built into the browser or some component built on top of the browser.
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.
> I don't see what difference it makes whether you use some component built into the browser or some component built on top of the browser.
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.
> Websites that re-implement text boxes, history, scrolling, so many things, never get every detail right.
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.
> 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.
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.
> 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.
> This article ultimately supports this by showing us exactly how half-baked this particular browser feature happens to be.
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"
You say "no solution" like form validation isn't one of the most common things that all web forms do today. Solutions exist. What I'm trying to say is instead of browser building adding high-level functionality like this they should simple continue to provide better ways for us to do it ourselves.
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.
I totally understand this. Having DOM elements as an entry to some API isn't the best thing.
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.
> On submit, the first field that needs attention gets focused automatically
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.
Strongly disagree. There are so many places where the browser itself provides a reasonably good user interface, and web developers fuck it up - scroll hijacking and history manipulation being two of the biggest examples. I suspect that one of the reasons we ended up in JS-hell is that HTML and browser built-in functionality lagged behind user expectations for so long. If browsers had offered the equivalent of AJAX and DOM element replacement early on, heavy use of JS might never have caught on.
The browser only reluctantly accepts its role is an application UI platform. Every problem, including the ones you describe, come from the disconnect between what a browser is and what it is used for. The browser is always going to lag behind user expectations so that's why I think it's the last place we should put that functionality.
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.
No it isn’t. It fucking sucks. Most everyone who learns HTML comes across the validation attributes, the god awful built in date pickers and other shit, and they throw it out in favour of custom built better UX implementations. Maybe in the past we would have been clueless because, well, they didn’t exist, but today they do. And they’re junk.
Call spade a spade. Don’t call it heavily underused.
It's extremely frustrating to me how reliably the anti-JS crowd on HN promotes this sort of "just use HTML / CSS" content. Having a general purpose programming is obviously beneficial for application development. There is no arguments to not use Javascript besides "some users (ie the people here on HN and virtually no one else) don't like to enable Javascript"
The last example is bad. You shouldn't scream at your users before they even had a chance to enter the required information so the second password field should not be marked red until the user either is done entering text there (onblur) or tries to submit the form.
That's totally true! Invalid states shouldn't be shown sooner than necessary
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
This is one of my big gripes - when apps are trying to get ahead of me with validation or submission. When I'm entering a 2fa code, I don't need a big red error telling me that the code must be 5 digits before I'm even finished. Worse is when they immediately auto-submit upon entering the last digit, so if I made a mistake I can't backspace and correct it
That's nice, I'll use that next time. Although it always feels kind of bad to write client side validation code because you're going to have to do the same checks on the server side anyway.
I find it sad that so many frameworks leave the developer to duplicate server-side and client-side validation. There are obviously some things you can't reasonably validate on the client, but I'd like to see more automated ways to take backend constraints and check them on the client too.
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...)
One of the compelling reasons to use Javascript-based frameworks like nextjs or remix.run is that you can reuse the same logic + types on the frontend and backend.
With Typescript, this is now my preferred way to build full-stack sites.
You could use something like json-schema to define constraints, and use json-schema validator libs on the front and back end to validate the form data against the schema.
You still need to handle the "what happens next" part on each side, but at least your validation rules are shared.
Why is that bad? Both have uses:
1. Client-side validation is for immediate feedback for the user.
2. Server-side validation is to block malicious actors
Built-in validation is pretty much the only reason I use forms.
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.
Do we finally have a standard solution for input masks ? 25 years ago I was struggling with this while my fellow desktop app devs had good input masks in their widgets, with easy to use pattern syntax. That would be embarrassing if not.
Guilty. Recently, when I was involved in a project that required a lot of attention to forms, I ended up overlooking the importance of basic simplicity. I regret it a bit. Thanks for sharing your perspective.
Are we seriously talking of HTML by using React examples? The article doesn't even explicitly aknowledge the fact that it is written within the context of react.
That's weird! Have you tried submitting the forms in the examples?
The custom messages are supposed to be shown in the native browser validation tooltips. The support for those is quite good! Even on mobile browsers
everything html offers more exotic than playing text leaves a bad taste in the month thanks to bad implementations.
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?".