State of React uncontrolled forms in 2022

Forms are the backbone of the web – still in 2022! So for a good start into the year, I decided to refresh my knowledge on the current state of web forms with React. It's actually quite nice what you can achieve easily with uncontrolled React form components and Constraint Validation API. Use the platform and let the browser do most of the heavy lifting!

The full form of this demo
The full form of this demo

This demo is based on static HTML export with nextjs. Please refer on their documentation for further details.

Main foci

Accessiblity

To provide basic accessibility, semantic HTML elements were used. Invalid states result in aria-messages which are connected to the input-elements through the correct attributes. In the accessibility section of the web.dev tutorial, they use aria-describedby. I actually think that aria-invalid combined with aria-errormessage is a stronger solution and prefer that. If anyone has better experiences in this regard, I would be very happy to receive feedback.

Another great accessibility enhancement were focussing the first invalid input element when trying to submit an incomplete form. Also rendering visually hidden information (e.g. <fieldset> with a <legend>) is important to provide users with visual impairments with them same information.

Usability with disabled JavaScript in the client

Isomorphic React with pre-rendered HTML gives a lot of power in our hands. But with that, I think, comes the responsibility to provide a good experience for users who don’t have client-side rendering (CSR). Still in 2022!
The form in this demo can be used without CSR. Of course, some features, like revealing password input, or better validation requires JavaScript in the client. However, this can be seen as a progressive improvement. When CSR is available, it adds attribute novalidate to the form and therefore disables basic HTML form validation. But even with disabled JavaScript in the client, submit will call the URL of action prop with the preferred method and still provide basic validation and a workable form.

Client-side validation

Client-side form validation is always a user-experience enhancement. In general, I combined HTML validation attributes plus custom JavaScript validation functions. The attributes provide basic validation for scenarios with disabled CSR.
Which rules result in HTML attributes are configured here (as a start). All other validation constraint will be handled with custom validator functions. They should therefore be available here. In this configuration, validation attributes have a higher priority compared to custom validator functions. For example if we decide to delete required from the htmlValidationAttributes, we should add a validator function with the signature of () => (value) => boolean and handle it in createValidator.

The properties of the ValidityState Interface are a bit wild in my opinion and not always attributable to the corresponding HTML validation attribute. But it basically says "yes, I am valid" or if not, it gives you a reason. I also started adding a mapping from the validation attributes to the property of the ValidityState.

Styling

Nowadays, it makes definitly sense to use accent-color. This gives you at least a little power to syle “hard-to-style” elements like input[type=checkbox] and align them with your brand style.
Also the combination of outline and outline-offset is really nice, since this is a very common visual requirement for focus states, and often needed some quirks to achieve that.

Conclusion

In the end, this is a very simple solution. But if you like this approach, using the browser’s capabilities with uncontrolled React form elements, React Hook Form might be worth to be checked out. Thanks for reading!

Repository on Github

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Thomas Rutzer

hay I’m Thomas, specialized in crafting unique interfaces & interactions for the browser platform. Meet me on twitter or github: @thomasrutzer