Introduction
Form validations are necessary when building any solution needing user input, as users can insert undesirable values erroneously or intentionally. To ensure the values received are as expected, we may want to handle the validations both on the client side and server side, and this provides early feedback for the user when interacting with the form as well as accurate response from our backend systems with readable messages to relay to the user, this could be an error message, an intermediary message for a multi-stepped process, etc.
It is essential to think of the best UX (user experience) for the end users of whatever platform, application or tool we build, providing relevant titles and placeholders and handling the different states (e.g. loading, disabled, error state) accordingly with accessibility in mind.
Luckily, form validations are not a new innovation, and we don't need to "recreate the wheel" in writing complex logic from scratch, as there are a couple of libraries already in existence that people, teams, and communities have spent time building that we can extend or use to create powerful/robust forms. Some famous examples include Formik, react-hook-form and redux form with schema builders like Zod and Yup.
My recommended process for building dynamic forms
- Handshake on a contract with field values expected by the backend to plan accordingly on the front end and choose your form library based on your use case.
- Depending on your form's complexity, you might have to map the values you receive from your backend system to an acceptable format for your frontend form library/handler. Extra notes (it would be helpful to have tests for this mapper function(s)).
- Pre-fill your form with values received from the backend (if applicable) and ensure your action buttons are disabled when not dirty (field values haven't been changed).
- Handle client-side form validations on your desired event (e.g. onBlur, onTouch, etc.) and show relevant error messages.
- You might want a separate validation approach for a save progress action and a submit form action.
- When the form is submitted, depending on whether the validations are passing from the previous step, you may want to map your form values to the acceptable format as agreed with the backend contract (tests would also be helpful here).
- Handle loading states when the backend is processing the form; once a response is received, ensure you relay a readable message to the user; this could be a success message, an error toast, or a list of issues with the values received; you may also want to highlight the problematic fields.
- If the form is multi-stepped, you may want to handle the state of the form accordingly, e.g. show a progress bar, show a success message, etc.