erikras.com
HomeAbout

Solid Final Form – Proof of Concept

Since its inception, Final Form was designed to outlive existing frameworks.

Posted in 🏁 Final Form, Solid JS
November 26, 2022 - 5 min read
Solid Final Form – Proof of Concept

Five years ago, I challenged myself to create a form state management library that was framework independent. In 2017, the idea that maybe React wasn't the best place to manage application state was not nearly as common as it has become. Formik had just been released and took all of the form library NPM downloads for the following few years. Formik went all-in on React for state management. The current King of Forms in React is React Hook Form, again, betting all the marbles on React's state management prowess.

From the very beginning of Final Form, it was designed to outlive existing popular frontend frameworks. Form state is two things:

  1. more complicated than you think
  2. not inherently related to any frontend framework

When our great grandkids are filling out their applications for Space Academy, they are going to be entering data, be it with a keyboard or a neural implant, into a form field that is going to have some validation rules on it, and the UX is gonna SUCK because the engineers at Space Academy didn't spend enough effort making the form entry experience good.

Just because the form is rendered in the then-popular Neural4D-VR.js UI framework, the flow of the form data will be just like it is now.

Form State is framework independent.

Solid JS

I've been hearing rumors of this new React competitor getting more and more popular. I'd glanced at it a few times, but at a recent conference, I got to meet the creator, and generally sense the wind of interest headed in its direction.

The "no virtual DOM" and "reactivity" claims are incredibly intriguing.

[insert React is not reactive joke here]

What really put me over the edge to attempt what I'm about to present to you is realizing that Solid lets you tack on "directives" to your JSX, which are little functions that get to manipulate the DOM directly, a benefit of not having a virtual DOM. This could make a very interesting way to connect inputs to a form management library.

Especially if there were a form state management library that were framework agnostic... 🤔

Proof of Concept

What I'm about to show you is an example of what a Solid Final Form library might look like. It calls useForm() to create a form instance and expose its API. Potentially all form state could be exposed via Solid's signals. From the docs:

Signals are the most basic reactive primitive. They track a single value (which can be any JavaScript object) that changes over time.

In this proof of concept, I have only exposed values and isSubmitting, but Final Form has a veritable plethora of other form state it manages.

useForm() also gives us two directives, field and error. To connect an input (i.e. attach blur, change, and focus listeners) to Final Form, we:

  1. Throw a use:field directly on the <input/>
  2. There is no step 2, you're done already!
  3. How fun are <li> gags?

The field directive reads the name prop on the input and knows what field it is.

To show errors, we don't have a name prop, so we have to tell the error directive with:

<span use:error="firstName" />

Here's the full form component:

export const App: Component = () => {
// Create Form
const { error, field, handleSubmit, isSubmitting, values } = useForm(
onSubmit,
initialValues,
validate
);
// Calculated Signal
const formattedValues = () => JSON.stringify(values(), undefined, 2);
return (
<form onSubmit={handleSubmit}>
<h1>Solid Final Form 🏁</h1>
<label>
<input name="firstName" placeholder="First Name" use:field />
<span use:error="firstName" />
</label>
<label>
<input name="lastName" placeholder="Last Name" use:field />
<span use:error="lastName" />
</label>
<label>
<select name="favoriteColor" use:field>
<option value="">Choose a color</option>
<option value="#FF0000">Red</option>
<option value="#00FF00">Green</option>
<option value="#0000FF">Blue</option>
</select>
<span use:error="favoriteColor" />
</label>
<button type="submit" disabled={isSubmitting()}>
Submit
</button>
<pre>{formattedValues()}</pre>
</form>
);
};

In this 100-line proof of concept, what are the features we're getting?

  • Realtime client side validation (as you fix errors, they go away)
  • Tracking if a field is "touched" (focused and then blurred) to only show the error if a user has visited the field or attempted to submit the form
  • Blocking submission when there are validation errors
  • A signal to tell us if the form is being submitted
  • None of that "Is the whole form rerendering? Waaahhh!! 😭🍼" nonsense that React gives us
  • Render props? What are those??
  • A robust battle-tested framework (300k weekly downloads) for managing our form state

Sandbox

Future

At the time of writing, this is just a fun Saturday morning fun project. I don't really feel like I have the bandwidth right now to pursue maintaining another open source library, but I'd be happy to work closely with anyone who would like to take this and run with it. You can find me on Twitter.

Discuss on Twitter

© 2024 Erik Rasmussen