Forms Without Frustration: How We're Building a Cross-Platform Form Engine
Most developers probably don't see building forms as a dream project, but rather a nightmare. It's often repetitive, error-prone, and not particularly exciting.
One example at Gomibo Platforms is managing the properties of products offered across the websites powered by our software. Having to manually define and update all those fields, validate input, and process the data isn't something we want to spend time on.
That's why we're building Dynamic Forms: a system that lets us define forms once, use them across front-end and back-end applications, and render them dynamically based on a shared protocol. This provides a consistent structure across projects and services, reduces duplicated logic, and makes collaboration between teams easier.
Our goal is simple: every business employee or engineer should be able to create a form without needing specialized front-end or back-end knowledge.
How It Works
At its core, Dynamic Forms uses a JSON-based schema that describes form fields, validation rules, grouping, metadata, and more.
These schemas are generated within the applications where they're used, based on data retrieved from the back-end. We considered having individual services generate the schemas through their APIs. However, this would require endpoints tailored to specific use cases in specific applications, which we wanted to avoid.
Example field definition:
The JSON example above defines a field where a user enters their first name. It includes the field type (such as a string or number), some metadata, and basic validation rules.
The full JSON scheme contains additional information about the form and can also be used to group fields together. For example, the first-name field could be part of a broader "Personal Information" group alongside fields such as last name. When rendering the form, this grouping can be made visually clear.
Example of a rendered form field
Front-End and Back-End Libraries
We've built two libraries to implement the Dynamic Forms protocol: a front-end library using JavaScript and React, and a back-end library using PHP.
Both follow the same protocol, but each has a different responsibility:
But why reinvent the wheel and build another form library when so many already exist? Partly because we're engineers, and we simply enjoy building things ourselves. We also considered existing libraries such as React Hook Form. However, these would still require an additional layer to support our Dynamic Forms protocol. Our main advantage is having one shared form definition that works across applications and services, making development more consistent and easier to maintain.
This simplified example shows how the React library works. It defines a general form component and a reusable text input component for all fields containing text. This allows developers to build forms without having to create each input field separately.
From Our Original Back Office to Hub
Example of legacy back-office interface
Although our old back-office interfaces worked well for many years, there was room for improvement. They were built when our company was growing quickly, and the main priority was being able to make changes fast. Our developer team was not as large and there were hardly any guidelines for user interfaces.
Fifteen years later, a lot has changed, both in our company and in what we expect from our software. For example, we now have many more international customers and colleagues, making translations essential. As the screenshot above shows, these weren't always available in our original interfaces. As we further developed our SaaS model, we needed to advance the tools we build for external telco partners to use.
Hub is the new and improved back-office system we’ve built. One of the projects we needed to develop for this involved creating interfaces for managing product information.
Products have general properties, such as color, but depending on the product type, they can also have more specific ones, such as noise cancellation for earbuds. These properties help inform customers about products and allow them to filter and search.
A single product can easily have more than 100 properties, which means forms need to be generated dynamically based on those properties. This also includes basic client-side validation, such as preventing users from entering text into numerical fields.
Although the actual validation happens in the back-end, client-side validation improves the user experience. After all, getting feedback while filling in a field is much better than receiving a long list of errors after submitting the form.
Example of fields related to a phone’s connectivity options in the product information interface.
Challenges and Next Steps
Although development of Dynamic Forms is underway, there are still some challenges to solve. For example, managing state in React can become complicated when forms contain many fields.
To address these challenges, we're considering integrating an existing form library. After all, our goal isn't to build everything ourselves, but to create reliable tools that make developing and maintaining forms easier.
The product information interface has already demonstrated what's possible. As more of our customers start using Dynamic Forms within the Hub, we'll continue improving the libraries based on their feedback.
Ultimately, this work is about more than making life easier for our customers. Consistent and user-friendly interfaces help telco teams manage complex product information more efficiently. This also helps ensure that end customers receive accurate and consistent information across sales channels.
Dynamic Forms is a good example of how we continuously improve our commerce platform. By simplifying complex processes behind the scenes, we can focus more on what matters: helping telcos deliver better experiences to their customers.