Most form builder tools (maybe all of them?) use drag-and-drop visual editors to construct forms. And that made sense - it was accessible to everyone, non-technical people could create forms with no problem. However, drag-and-drop has serious limits - especially around dynamic behavior and calculations. Code is much more flexible in that regard. You can use all the power of, say, TypeScript to declare intermediate variables, use conditional logic, loops, all math operations, lists, etc. and use all of that to build calculations or even mutate the form dynamically. The only problem was that no one - except software developers - knew how to code. But that's no longer the case since the boom of AI and LLMs like ChatGPT or Claude. Today anyone can translate plain English into code - and create far richer forms than what's possible with old-school drag-and-drop.
Below I'll describe my attempt to build a new-era, code-first form builder whose goal is to be AI-native and let everyone harness the flexibility and power of code.
The concept
The whole thing revolves around a single TypeScript file - form-builder.d.ts. It defines all available field types, configuration options, and methods. That file is your contract. Your job as a user is to write a function that receives a FormTs object and builds the form using it:
export function cleaningQuote(form: FormTs) {
const details = form.addSubform('details', { title: 'Project Details' });
details.addRow(row => {
row.addDropdown('service', {
label: 'Service Type',
options: [
{ id: 'basic', name: 'Basic Cleaning ($80)' },
{ id: 'deep', name: 'Deep Clean ($150)' },
{ id: 'moveout', name: 'Move-out ($220)' }
]
});
row.addInteger('sqft', {
label: 'Square Footage',
min: 100
});
});
}
That's a working form. A dropdown and a number field, in one row, inside a section. The pattern is always the same - add sections, add rows, add fields. If you want an LLM to generate a form for you, you just give it the form-builder.d.ts file as context and describe what you need. The AI knows exactly what's available because the types tell it everything.
Everything is reactive
Here's the thing that makes code-based forms actually powerful. Almost every property in FormTs accepts something called ConfigValue<T> - which can be either a plain value or a function. If it's a function, it gets re-evaluated automatically whenever any value it reads changes.
So instead of writing label: 'Price' (static), you can write:
label: () => {
const service = details.dropdown('service')?.value();
return service === 'deep' ? 'Deep Clean Price' : 'Estimated Price';
}
And it just updates. No event listeners, no state management, no manual wiring. This applies to visibility, labels, options, validation, min/max constraints - basically anything. Want a field to appear only when two conditions are met? Easy:
isVisible: () => {
const service = details.dropdown('service')?.value();
const sqft = details.integer('sqft')?.value() || 0;
return service === 'deep' && sqft > 2000;
}
Most visual builders can technically handle this with enough clicking. But the moment you have five conditions referencing computed values from other sections, the UI becomes a maze of nested dropdowns that no one wants to debug. In code, it stays a readable function no matter how complex it gets.
And the real payoff - computed prices. You can add a PriceDisplay field that calculates its value from other fields in real time:
row.addPriceDisplay('total', {
label: 'Estimated Cost',
computedValue: () => {
const prices: Record<string, number> = { 'basic': 80, 'deep': 150, 'moveout': 220 };
const service = details.dropdown('service')?.value() || 'basic';
const sqft = details.integer('sqft')?.value() || 0;
return prices[service] + (sqft * 0.05);
},
variant: 'large',
suffix: () => recurring ? '/visit' : ''
});
The user fills out the form, the price updates instantly. No "calculate" button. No page reload.
Live preview
The editor is a split view - code on the left, live form preview on the right. As you type, the TypeScript gets compiled and the form re-renders automatically. You see your changes in real time, no need to save or refresh anything.
You can also resize the preview to simulate different devices - mobile (375px), tablet (768px), or desktop. Useful when you're building forms that need to work well on phones.
And if you want to customize how your form looks, there's customStyles - it accepts an object of CSS properties that get applied to the field or section. It can also be a function, so you can have dynamic styling:
customStyles: () => {
const total = getTotal();
if (total > 500) return { backgroundColor: '#dcfce7', border: '2px solid #22c55e' };
return { backgroundColor: '#f3f4f6' };
}
The form highlight turns green when the total crosses $500. Stuff like that is trivial in code and impossible in most visual builders.
Why code is actually better
Beyond calculations and reactivity, code gives you things that drag-and-drop never will:
Version history. Every change is tracked. The editor has a built-in diff viewer - you can compare any two versions side by side and see exactly what changed, line by line. If the AI broke something, you see which lines it touched and can revert.
Reusable logic. Need the same discount calculation in three places? Write a function once, call it wherever. In a visual builder, you'd copy-paste the same rule three times and pray you update all of them when the business logic changes.
Comments. You can write notes explaining why something works a certain way. Six months from now you'll know why that weird 25% exception exists instead of someone "fixing" it thinking it was a mistake.
Search. "Where do we apply the 15% discount?" In code, you search for 0.85 or discount and find every instance. In a visual builder, you'd click through every field in every form.
Sharing. Your form is just text. Copy it, send it over Slack, paste it into another editor. No export wizards, no file formats.
Built-in AI
The editor has AI built right in. You type what you want in plain English - "add a dropdown for service type with basic, standard, and premium options and a price that updates based on selection" - and the AI writes the code. It understands the full FormTs type system, so the generated code is usually valid out of the box.
But here's the part I think is more interesting. FormTs has an API. You can create and update forms programmatically:
POST /api/forms
{
"name": "Cleaning Quote",
"code": "export function myForm(form: FormTs) { ... }",
"versionNo": 1
}
Which means tools like Claude Code, Cursor, or any AI coding assistant can build and deploy forms for you directly from your terminal or IDE. Give it the form-builder.d.ts types, tell it what form you need, and it can create it, push it through the API, and you get a working embeddable form without ever opening a browser.
AI Interviewer
This is probably the most experimental feature. You define your initial form as usual - a few fields collecting basic info. Then you enable the AI Interviewer and give it instructions like "Ask clarifying questions about the user's project. Focus on timeline, budget, and specific requirements."
When someone fills out and submits the form, instead of just ending there, the AI reads their responses and generates follow-up questions. It adds new pages to the form dynamically based on what the person actually said. So if someone mentions they need the work done urgently, the AI might ask about their deadline and whether they're flexible. If they mention a large space, it might ask about access and parking.
It's like having a conversation, but structured as a form. You set the max number of follow-up rounds (1-10), write the instructions, and the AI handles the rest.
Try it
That's FormTs in a nutshell - a code-first form builder where the code is TypeScript, the AI writes it for you, and everything updates in real time. I built it as an experiment to see how a code-first approach to form building would work in practice. I'm pretty happy with how it turned out, but I'm still looking for early users who'd want to give it a spin and share their feedback.
If you're curious, the whole thing is free to try at formts.com. There are a bunch of calculator templates you can open and look at the source code to see how things work. Or just try describing what you need to the AI and see what it generates.
Happy to answer questions in the comments.

Top comments (0)