Forms
The useForm() hook from @vaadin/hilla-react-form binds the fields of a React view to a Java type. It keeps the value of the form, validates it with the Bean Validation constraints of the Java type, and submits it to a browser-callable service.
- Validation
- The Bean Validation constraints that forms check in the browser, validators of your own, and errors that a service reports.
- Form State
- The value, the dirty and invalid states, and the errors of a form and its fields, and how to change the value of a field from code.
- Nested Objects & Arrays
- Bind the properties of nested objects, split a form into components, and add and remove the items of a list.
- Field Components
- The Vaadin components that the field() function binds, and the Java types of the properties that they edit.
- Form API
- The hooks that bind forms in React views, their results, and the types for validation.
Form Models
For each Java type that a browser-callable service uses, Vaadin generates a form model next to its TypeScript type. For example, the model of Person is in PersonModel.ts, beside Person.ts. See Generated Files.
A model describes the properties of the type and their constraints. It doesn’t contain a value. The examples on these pages use this record and service:
Source code
Person.java
Person.javaSource code
PersonService.java
PersonService.javaThe package of the records is annotated with @NullMarked, so their properties are non-nullable, except birthDate. See Type Nullability.
Binding Fields
Pass the generated model to useForm(). Then spread the result of field() on each field component, with the model of its property as the argument:
Source code
person-form.tsx
The field() function connects the component to the form. It sets the name, the value, the required state, the invalid state, and the error message of the component. It updates the value of the form when the user changes the value of the component. The components that it supports are listed in Field Components.
The model of the form has a model for each property of the type, such as model.firstName. A property that is an object has models for its own properties, such as model.address.street. See Nested Objects & Arrays.
Loading a Value
The read() function sets the value of the form, for example the value that a service returns. It also makes the value the default value of the form, and clears the validation errors. Passing null or undefined clears the form.
The form has a value before read() is called: each property has the default value of its model, such as an empty string for a String property.
Two more functions change the whole value:
reset()-
Sets the value back to the default value, which is the value last read or submitted.
clear()-
Sets the value, and the default value, to the default values of the model.
Submitting
To save the value, pass an onSubmit callback to useForm(), and call submit(), for example when the user clicks a button. The submit() function first validates the whole form. When the form is valid, it calls the callback with the value of the form, and resolves with what the callback returns. While the promise of the callback is pending, the submitting property of the form is true.
When the validation fails, submit() doesn’t call the callback. It rejects with a ValidationError from @vaadin/hilla-lit-form, and the fields show the errors. Catch the error, so that it doesn’t become an unhandled rejection:
Source code
person-form.tsx
Other errors of the callback, such as an EndpointError, reject submit() as they are.
After the form calls the callback, it uses the submitted value as its default value. This happens also when the callback fails, for example when the server rejects the value. The form is then no longer dirty, and reset() returns to the submitted value. A submit that fails the validation in the browser doesn’t change the default value.
Server-Side Validation
The service validates its arguments again, as described in Parameter Validation. When an object from the form fails the validation, the call rejects with an EndpointValidationError. Then submit() shows each error in the field whose path matches the property of the error, such as address.street or phoneNumbers.0.number, and rejects with a ValidationError.
An error that matches no field is only in the errors property of the ValidationError, and the form stays valid. The errors of constraints on the method parameters themselves, rather than on the properties of the object, don’t match any field. A service can also report errors of its own, as described in Errors from the Service.