From my point of view, creating forms is, unarguably, one of the most boring and tedious programming tasks to perform when developing a frontend application. Worst of all, you are going to do it over and over. Therefore, we could consider it as a repetitive task and, hence, we, as software engineers, should find solutions that make us more productive.
At Divisa iT we are very aware of this problem, and we have implemented different solutions over time. From custom taglibs, used in long-forgotten JSP applications, to form creation wizards. This experience has provided us with a deep insight into the different form-based-application use cases.
When we started using REACT this problem raised again. We needed to develop forms, and we needed to develop them swiftly. My aim was avoiding as many monotonous tasks as possible, while focusing on a series of key goals such as:
Obviously, you could argue that we have created an opinionated solution. As a matter of fact, when you build something reusable you must take decisions. I mean to say, that it has work in a certain and well-defined way. In fact, I don’t know any library which isn’t opinionated to some extent.
In the following sections I’ll try to show you how we have implemented solutions to the different objectives described below.
Although there are several issues to consider, I’ll focus only on the main ones, such as:
Developing a form from scratch, and taking into account all these points is, in my opinion, boring and prone to errors.
That’s why, I have taken some decisions which drive to a more compliant final development. For example:
We are using, under the hood, react-i18next to translate all labels, hints, and placeholders. As a result, our developers should only focus on the form development and the creation of a translation file skeleton. Actual translation could be provided by a third-party or even a translation API.
As I told you previously, we use TypeScript and a strict separation of concerns. From forms point of view this introduces two interesting perspectives.
As I see it, we made an important effort to improve both the productivity of our developers and the end-user experience. Main results include:
In the first place, our custom components could be customized using a help attribute. Whenever the user hovers the help icon, help text is shown on screen considering all accessibility issues.
In the second place, some tasks such as checking the value of an input field, verifying if it’s required or even if there is a dependency between two or more controls is achieved in an extremely simple way.
Last, but not least, when we develop forms, we are sometimes in the need to solve some complex issues.
On the one hand, imagine a situation in which you are displaying two fields, but you want the user to enter data in only one of them. In fact, those are XOR based fields, one or the other, but not both. We have solved this problem introducing a custom component named UIAnyOf
On the other hand, sometimes we also need to develop repeating groups, you need to support arrays, to introduce add and delete buttons and even move-up and move-down ones. Our solution involves using a custom component named UIRepeatGroup, of course your model must support this structure.
As you could notice I have tried to design our solution as simple as possible. Moreover, I have also taken other decisions which help us to improve our development times.
When developing forms too many issues are involved. Solutions as this one provide mechanisms to improve both client time-to-market and developers productivity.