-
Notifications
You must be signed in to change notification settings - Fork 55
UIForm V3
Today, @talend/ui repository has a form package. It proposes 1 api, based on json schema format. This has been done to fill tcomp/tacokit, to let the backend services control the forms with json format based document.
Json is really limited and static, and this introduces limitations in the features. To overcome some of them, and to comply in tcomp/takokit lifecycle, we introduced triggers, to have an external entry to do custom actions (change of schema, dynamic/async validation, change of suggestions, …). But the implementation is really hard to maintain and synchronize. For example validation has 3 entry points:
- (backend) Json Schema: static validation on single elements
- (frontend) Component custom validation props: complex single element validation
- (frontend/backend) Trigger: static/async validation on global/single element(s)
The result is that
- Frontend developers struggle to create frontend-only forms, writing tons of json instead of components, without being able to fulfill complex cases
- Backend developers struggle too, trying to implement complex validations with json and UIForm limited features.
We need to open this implementation, to let frontend developers write their custom/complex use cases, and have a validation format flexible enough, that we can convert to the open implementation.
(TODO)
@talend/react-forms has a custom implementation. The json schema is present at every level of the implementation, from top level form to widget internal code. It’s very hard to extract the schema part to a top level to allow developers to use the widgets as components. A better and less costly solution would be to base the implementation on an existing library. The developers would be able to use the library (or the wrapper on it), and backend users would still be able to use our custom schema layer on top of it.
Github stars | Maintained | Contributors | Issues | |
---|---|---|---|---|
Formik | 19.1k | By @jaredpalmer | 268 | 376 |
React-hook-forms | 4.2k | By @bluebill1049 | 38 | 1 |
Weekly dl | Size | Dependencies | |
---|---|---|---|
Formik | 307k | 12.6kB | 9 |
React-hook-forms | 30k | 5.2kB | 0 |
Formik was created by @jaredpalmer who is very active in the frontend community. The library is very popular and well maintained. It has tons of contributors and more than 19k stars.
React-hook-form is quite young, it was created in march 2019 by @bluebill1049, but has risen quite fast, having now more than 4k stars. It is a very light library, with no dependencies. It has a documentation for advanced cases such as custom widget, accessibility, or wizard.
The goal is to compare the developer experience and the possibilities between the 2 libraries and our current implementation. We will focus on the component part, as we don’t want to break the api for schema part.
Basis
Scenario | Story |
---|---|
B1 | as a developer, I want to create a simple form with email and password, with submit function |
B2 | as a developer, I want to add a custom widget |
Validation
Scenario | Story |
---|---|
V1 | as a developer, I want to validate the email pattern and password requirement |
V2 | as a developer, I want to async validate the email, checking it’s availability |
V3 | as a developer, I want to do a complex validation, with values dependencies |
Advanced
Scenario | Story |
---|---|
A1 | as a developer, I want to set a field required depending on another value |
A2 | as a developer, I want to show/hide a new field depending on another value |
{
"jsonSchema": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
},
"password": { "type": "string" }
}
},
"uiSchema": [
{
"key": "user.email",
"title": "Email"
},
{
"key": "password",
"title": "Password"
}
],
"properties": {
"user": {
"email": "[email protected]"
}
}
}
import { UIForm } from "@talend/react-forms/lib/UIForm";
import data from "./schema.json";
function ExampleForm() {
return (
<UIForm data={data} onSubmit={(event, values) => console.log(values)} />
);
}
On a simple form, it stays simple. You have 3 parts:
- json schema: defines the model
- ui schema: defines the widgets
- properties: defines the default values
import React from "react";
import { Formik, Form, Field } from "formik";
function ExampleForm() {
return (
<Formik
initialValues={{ user: { email: "[email protected]" } }}
onSubmit={data => {
console.log(data);
}}
>
{args => {
const { isSubmitting } = args;
return (
<Form>
<div className="form-group">
<label>
<Field type="email" name="user.email" />
<Field type="password" name="password" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
);
}}
</Formik>
);
}
Formik offers to write javascript instead of json. Each form and field components comme from
Compared to the schema
- the structure is tied to the field names
- the default values are passed at Formik component level
There are some extra features to manage some status. In the example above, the isSubmitting
flag allows to avoid submitting twice the form.