Creating Dynamic Forms with Typing and Validation: An Efficient Solution Using React, Zod, and React Hook Form
Vasilii Yatsyuk
React / TypeScript / Next.js Frontend Developer | Transforming Complex Ideas Into Intuitive Web Applications
Developing dynamic forms in a web application is a task that demands flexibility, strict typing, and proper data handling. Today, I want to share my experience and explain how I approached solving this challenge. My solution might not align with all best practices, but it is practical, tested, and effectively addresses the task at hand.
Problem Description
I needed to implement dynamic forms that were fully configurable based on data received from the server. This data described:
- Form Structure
- Parameters for Each Field
- Field Validation Rules
- Data for Form Submission Buttons
Additionally, the form needed to:
- Be dynamically generated based on a JSON configuration.
- Have strict typing enforced with TypeScript.
- Support validation based on rules provided by the server.
- Populate fields with default values.
Solution Description
To implement the dynamic forms, I used the following tools:
- React for rendering components.
- React Hook Form for managing form state.
- Zod for typing and validation.
1. Form Typing
To ensure strict typing, I defined types for all form components. For example, inputs include standard fields such as name, label, type, placeholder, width, defaultData, as well as validation rules. This allows the server to specify field parameters that will be correctly processed on the client side.
2. Processing Data from the Server
Data from the server is transformed into a unified structure using the populateFormWithData function. This function assembles form fields, buttons, and other parameters into a cohesive structure.
3. Generating Default Values
Default values are automatically generated for all fields based on their type.
4. Form Validation
The server provides validation rules, which are converted into a Zod schema. This ensures strict data validation on the client side. Example:
领英推è
5. Setup field width
When rendering each form element (input, select, checkbox), we ensure that their width matches the data received from the server. This approach makes the form highly flexible and adaptable to various layouts and user interfaces.
To set the width, we use a simple function, getFieldWidth, which calculates the value based on the provided width parameter. If the field's width is 100%, it takes up the entire available space. For other cases, the width is calculated while accounting for a small margin between fields.
6. Form Rendering
The form component leverages React Hook Form to manage state and validate data. Example:
Challenges and Solutions
Dynamic Validation
- Challenge: Converting validation rules from the server into a Zod schema.
- Solution: The generateZodSchema function, which automatically generates a schema based on the field type and its rules.
Generating Default Values
- Challenge: Setting correct default values for each field type.
- Solution: The generateDefaultValues function, which handles the generation of appropriate default values for all field types.
Typing
- Challenge: Integrating strict typing into dynamic forms required a well-thought-out data structure.
- Solution: The FormField and UiInputValidationRules types ensured safety and predictability when working with forms.
Results
My solution allows:
- Generating dynamic forms based on server-provided data.
- Ensuring strict typing and flexibility.
- Easily adding new components and validation rules.
This solution is already used in production on aterra.nx.md and has proven its effectiveness. I’d love to hear your thoughts and suggestions for improvement! ??
Daydreamer @UFL Game | ex-EA, Crunchyroll
3 个月????