Building data-driven dynamic forms with Remix, remix-validated-form & zod
Introduction
Modern web applications and sites often incorporate workflows to collect user input and enhance their user experience. These workflows can range from simple tasks like providing a name and email address to complex processes such as online checkouts or manufacturing orders.
Web forms play a crucial role in enabling these user input workflows. They allow users to input data through a browser, which is then collected, validated, and stored in a database for further use. Many form libraries exist for different frontend frameworks, simplifying the process of building forms. These libraries handle data validation, form state management, and error handling.
Building web forms can be straightforward. HTML provides a variety of built-in tags (components) that can be easily added to web pages. If you're using a frontend framework like React, you can use JSX within a component and leverage form libraries like React-Hook-Form. This combination allows developers to create sophisticated web forms with features such as data validation, error handling, and UI feedback for form submission status.
This approach works well when the form fields are static and known in advance, and there is a single flow of data entry.
But what if we need to change the flow of the inputs based on the user's previous selection or entry?
Data-driven dynamic web forms
The way to resolve the issue mentioned above is by dynamically building web forms in a data-driven manner. Let's consider an example: a user is browsing phones on a phone and plans provider's website. They choose a phone to purchase and proceed to the checkout process. During checkout, the provider offers multiple options for the customer to receive the device. They can either opt for Click and Collect, where they visit the store to collect the phone, or they can choose delivery to their address. Depending on this selection, the flow of the checkout process needs to change. If the user selects Click and Collect, they need a workflow to find the nearest store based on their location. On the other hand, if they choose delivery, the user needs to provide their delivery address.
The easiest approach would be to build all the logic within the form component itself. However, this approach has a few drawbacks. It would result in tight coupling between the business logic and the UI component, which would hinder the separation of concerns within the web application. Additionally, if the business logic changes, recreating the form component would require additional development work and a new release.
A better approach is to create a generic form type that can accept a configuration. This configuration would determine the relevant input fields, allowing the use of the same form libraries for all the heavy lifting. If the business needs to change the business logic or flow of the form, they can simply modify the configuration to meet their requirements.
How to create a data-driven dynamic form?
The principles of creating a data-driven form remain the same regardless of the web framework you choose. In this example, we are using the Remix frontend framework and utilizing the remix-validated-form and zod libraries for form submission handling and input field validation.
While this article does not cover the creation of highly complex data-driven forms with different workflows based on user selection, we will take a simplified approach. Our approach involves using an external configuration to create a multi-step workflow, incorporating input field validation, section validation, and form submission. This will demonstrate the end-to-end process.
For our example, we will build a simple web app that enables users to book an airport drop-off service from their address. We will incorporate scenarios for selecting the vehicle type based on the number of people, total items of luggage, and additional services such as including a child seat or mobility access. The configuration will be provided as a JSON object from an API, allowing the form to display different sections. Each section will cover relevant details such as trip information, vehicle and services selection, and customer details. We will use the remix-validated-form library and zod to validate the input fields and track the form submission status. Finally, once the form is successfully submitted, we will display a submission report.
- Setup sass and Carbon Design System for building the UI components and applying app level styles.
- Create the wizard component which makes use of sections and ui components
- Add remix-validated-form and zod for schema and section validation and form submission states
- Show the summary section