TL;DR? I made a library to compete with Formik and React Hook Form called "HouseForm". It would mean a lot if you looked at it, gave feedback on i...
For further actions, you may consider blocking this person and/or reporting abuse
We definitely need a good library for form management. Not Formik, nor R-H-F fit the bill, in my subjective view. You touch some great points in the article but (aside from code verbosity) I'm concerned about the following. For text inputs
onChange
validation is very expensive (1 validation per character).onBlur
validation requires to switch focuses back and worth, providing a somewhat clunky UX. I typically validate text inputs ondebounce
, so I'm surprised this approach is not even mentioned in the docs or repo. Though maybe adebounce
d function can be provided toonChangeValidate
– I need to give it a try :)I believe you should be able to add
debounce
toonChange
pretty trivially, but would have to build a POC for it.Could you add a GH Discussion or GH issue for this problem so that I can remember to investigate?
github.com/houseform/houseform
Kudos to anyone who wants to make form validation nicer.
I don't have your headless restriction, and am unsure what that entails since I've never used React Native, so take what I say with a bag of salt.
I couldn't use your Field component because I'm on react-bootstrap so I'm already using someone else's Field component, and all the css etc that goes with. That's one thing I notice a lot with form helper libraries is "who gets to use their Field component and who has to dance around that? Is it css-first or js-first?"
I also don't like the function-as-children syntax. I understand it fine but it just looks really busy. I understand this isn't really a concern of yours though.
Related to the above, I would definitely say make a helper for functions of the form (e) => setValue(e.target.value) since your users will be writing that a lot. Make a version of setValue that accepts the whole event. User should only write onChange={setValue} and similar. It would also help cut down on punctuation.
I'm interested in how HouseForm deals with multiple validation errors at once from the same onBlur or whatever. How to write onBlurValidate that checks both email valid, required, belongs to the current domain, and has a non-tomato fruit in it, and shows all four validation errors at once should it need to? Currently it looks set up so only one *validate event can have one error.
Anyway, very nice work.
First; sincerely thank you for providing this feedback. Any feedback provided in a sincere way is worth more than gold.
You mentioned that you don't have my headless restriction, but in the very next line you presented a key reason why we went forward with the headless concept; It enables you to use any CSS or UI library you want with HouseForm.
stackblitz.com/edit/houseform-v1-e...
The above link is HouseForm integrated with React Bootstrap - I'll be adding it to our docs pages shortly - it was a seamless process that took me 10 minutes and I've never used React Bootstrap before. 😄 I didn't have to fiddle with an
as
key or do some strangefor
trickery, nothing like that.As for the function-as-children syntax - I hear you. It's a mixed bag overall for sure, but I'm not convinced yet that it's better than a
render={() => {}}
API, especially when you can do something exceedingly similar with thechildren={() => {}}
explicit syntax. If you have suggestions of how you'd improve this, let's chat more in a GH issue or GH discussion.As for the
e => setValue
trick - I think making a helper function will be detrimental rather than a boon. I do a fair bit of mentorship in programming, and have often come into questions of "how do I get X to work with Y?", and official recommendations throw people off hard when they're not accurate for their specific use-case. While the helpere => setValue()
function might work well for React for web or some UI libraries, it won't be universal. This type of non-universal APIs often end up bringing in support tickets and headaches for all involved.Finally, to talk about your
multiple validation errors
- we support this right out of the box! This is why we do:Instead of:
If you do any testing and see that this isn't the case, that'd be a bug, which we'd love to learn more about with a GH issue.
Once again, thank you so much for taking the time to write this. If you have any additional thoughts (or replies to the above), let me know.
Super fast update on this: We've launched a docs page outlining how to use HouseForm with external UI libraries. Even used the React Bootstrap example :)
houseform.dev/guides/ui-libraries....
They specifically mentioned being environment agnostic, so it wouldn't make sense to have a helper that is fully aware of the event of the environment it's running in.
Really interesting article and next time I'm building a greenfield react app I'll definitely look into this!
I had a very similar jourrney to you in the Vue ecosystem where the form libraries are either unmaintained, too tightly coupled to validation libraries, or have awkward/ugly syntax. The only difference was that I didn't publish my library because I couldn't face the public maintenance commitments of yet another OS project 😅
I like zod and that's why I would use houseform and even it being agnostic means I can even use it for server side validation, however I find these validation libraries's syntax always hard to grasp, but in all, nice work though!
I never seem to get Formik to work for me, which lead me to roll my own form handling implementation for every project. I've gotten deeply uninterested in other form libraries given I know how to write one myself.
It always irks me when a library unrelated to another library ties its implementation to that library. Great work but I think it's a recipe for disaster/irrelevance.
I'm not sure I follow 😅 HouseForm has zero direct dependencies and only two peer deps: React and Zod (Zod is optional). It doesn't build on top of Formik, and doesn't even use the same API.
I'm unclear how HouseForm would fall under:
Isn't the "onChangeValidate" for "Field"s tied to zod. It's particularly expecting a zod validator
Not really. It's expecting either:
If Zod isn't installed, either will still work. We have docs on this here:
houseform.dev/guides/basic-usage.h...
At the bottom. We could (and will) do better to highlight non-Zod usage in our docs
I get that one can write their own custom validator that mimics the zod API. But that just highlights my point, your validation step is explicitly/implicitly tied to zod. Which is one problem I always run into when trying to use form libraries out there.
Hence why I roll my own which doesn't tie me to any particular validation library. I understand that it's hard to create a form library that handles validation without somehow owning the validation step. You don't have to take my opinion seriously, just highlighting my frustration with form libraries.
But looking through the codebase I saw this
in
which is more like what I was expecting for form validation not tied to any validation library. So I guess I was wrong
Right, this is what I was trying to point out 😅 You can pass a custom function with validation that returns a promise. Helpful when wanting to avoid Zod and/or do async ops
Congratulations on such a great library, i have been using it in my own prod apps and really enjoying it.
Thanks so much for the kind words and the support! It was such an awesome surprise to wake up one day to the introduction video of HouseForm on your channel! 🎉
What an amazing library, I was looking for alternatives to Formik and React Hook Form, I just found this for my personal project I will be using it!
Thanks so much for the kind words! :D
Let me know if you have any feedback as you use it - I'm eager to improve the library as much as possible.
I mean, I need React support though. Our applications are written in React Native (for various buisness reasons). I'm not sure that "Replace React" is a solution here.
I really like how react-hook-form handles when to validate: initially, it's on blur, then on submit, and if you submitted with mistakes it becomes on change (saying this approximately, it may be a more complex logic). This is the best for UX, so, before a form submit, user is not bothered with error messages, and after non successful submit they are clearly messaged what to change and validation message goes away right after being corrected.
I don't know, maybe your use cases are very different from typical ones, and this way of UX doesn't work for you well, but for me it's hard to imagine why would someone want to set up three different validations on the same input for on change, on blur, and on submit.
Also it's not clear what's bad about defining a whole form schema with Zod, it even gives you properly typed result afterward in the submit handler. Setting validation on each field separately seems to be more cumbersome.
Truth be told, it's just a different philosophy. Our buisness has pretty stringent requirements of what kind of requirements to do and when.
There's nothing wrong with having less control over that flow in exchange for simple to use relatively straightforward UX - just a different set of priorities.
More cumbersome? Maybe? I think most will only use
onChange
and call it done.More flexible though? 100%.
What's more, you can still use an object schema and use:
In the
onXValidate
functions in HouseForm.This is all to say; HouseForm fits our needs well but may not fit everyone's needs. That's OK - we admire and respect the other library's efforts! 😊
Don't you think it's a problem with UX? So you just start entering your name or email, and it immediately tells you that name is not long enough or email is not valid.
Developer may call it done, user may be fine with it, but what if your client will see it and will ask to change, but you can't do it as gracefully as with react-hook-form because this library wasn't designed for it.
So I think using onChange as a default option for validation is a mistake, and if client cares about UX they will ask to change this anyway, if client doesn't care of it much than it's just a not as good as it could be.
Of course, UX is subjective and for your case maybe it's better to display error messages right after entering first letter.
I think that's unfair.
This library has the ability to do pretty custom validation schemas - it absolutely was designed to do things like RHF's validation method, but be able to customize beyond that point.
Further, take a look at the example I was thinking of when I said
onChange
:frontendscript.com/wp-content/uplo...
This is a pretty common pattern to show the requirements of a password that can be done easily with HouseForm.
HouseForm is absolutely capable of pretty polished form UX without a ton of extra lift. Remember,
isTouched
andisDirty
are absolutely tools of the trade, as is conditional validation logic and more.Just to showcase that HouseForm can absolutely follow RHF's validation strategy...
Their docs claim that validation works like this:
onSubmit
onChange
How is this functionally different than:
stackblitz.com/edit/houseform-v1-e...
?
Truth is yours, I though it would be a problem, but in your example this looks simple to do.
In case when using RHF, usually no need to customize, but when there is a need I just add the
onChange
callbacks directly to the input, callonChange
from thecontrol
of controlled input, and use method of the libsetError
to set or remove the error.You know, it's a must have comments section "why you did it when X exists", but anyway that's great that you've made it, it has a different philosophy and syntax, having an alternative is always for good!
Haven't you been through lack of performance with big forms in Formik ?
You didn't mention it and it's the biggest downside I struggle with.
Especially with a lot of codependent fields and even when restricting validation on blur instead of on change events.
Does your lib handle this better ?
You know, you're not the first person I've heard this from. The challenge is that I haven't experienced this, have numbers to the contrary (more on that soon), and - until now - never had anyone provide me specific details about specifically when performance falls on it's face.
That's the bad news. Here's the good news: Performance is a key value for HouseForm. Remember, I'm using it in production for huge forms in our most business critical apps.
We actually have a set of benchmarks that we're developing to make sure we're on-par or beating common alternatives like Formik and React Hook Form (we're adding React Final Forms soon). While we only have three benchmarks currently, it shows that Formik actually outperforms React Hook Form when using RHF's
Controller
for 1,000 form fields and that HouseForm is within spiting distance of Formik:That's not all - we're actually still working on HouseForm's performance! We believe we may have a couple of methods we can still use to optimize the performance of the codebase. Some of the other performance improvements we've made previously is to conditionally recalculate the
<Form>
'sisValid
style helper variables if and only if the user is actually using the variables.That all said, now that you've been able to specifically highlight
onBlur
and codependant fields as areas of performance concerns with large-scale Formik forms, I will write benchmarks for those functionalities ASAP. I'll send a reply when we have some solid numbers for you.Thanks for the answer. I definitely try Houseform out.
Of course! Since my last message, I've added 3 more benchmarks, still looking generally in favor for HouseForm.
That said, I think I've found a possible major pitfall in terms of performance for all of the major libraries.
I've figured out a way to solve a potential performance issue, but the API is a bit wonky and I'm unclear if this is actually a problem or not.
If you're up for it and willing to share some insights as to what your performance problems are with large Formik forms, please let me know. I'd be happy to sit down and diagnose the root causes and solve them in HouseForm (or even in your app without a HouseForm migration!)
My DMs are open: twitter.com/crutchcorn or via Discord on this server: discord.gg/FMcvc6T (@crutchcorn on Discord)
@calag4n I just released version 1.3.0 of HouseForm, which includes a quick and easy way to drastically increase the performance of a form's re-render:
houseform.dev/guides/performance-o...
I'm not joking when I say that I've seen 70x performance increase in some specific edgecases in production.
I'd love to hear if this problem helps solve the performance issues you were running into with Formik.
I'm unclear what that would look like in React/JSX. What would you imagine this API to look like?
I'm feeling dumbfounded by the examples and their complexity of the syntax that's involved. Barely able to get what is what. Surely there must be a way to write same application logic without giving so much stress on my brains while I'm trying to parse these examples bracket by bracket and understand what it does?
I hear you - the "
children
as a function" syntax is unfamiliar at first.The challenge is that our primary goal is to remain headless - no UI elements rendered as part of HouseForm's API.
Moreover, we want to avoid making our API larger to add helper components (see Formik) to make that easier to read - with convos with other devs they're rarely used in production.
One way that you could chose to make the codebase a bit easier to read (in terms of brackets) is:
We chose to avoid recommending this for the official syntax because:
children
as a direct property is uncommonrender
, but then it suggests we want to add properties likeas
orcomponent
, which we do not for API surface reduction reasons.I know the brackets can be confusing at first glance, but with IDE extensions that change the colors of each bracket pair (or, built in, like VSCode), it helps a lot. Practice with it, and it might even make you more familiar with React's internals and why the syntax is the way it is. 😊
If you have a concrete example for how you think the syntax can be improved (while remaining fully headless), let us know; happy to discuss this further in a GitHub issue.
Just saying how it is. You'd be telling lies to your self if you think the syntax involved here is not extremely complicated.