Blog article

Forms that feel designed — the visual form builder

Published on August 1, 2021

Forms are where users spend most of their day. They are also, too often, where applications go to die: long scrolling lists of every field anyone ever asked for, irrelevant sections on display for everyone, validation that arrives too late to be useful. The fix isn't cleverness; it's a good builder. Ours lets every form in the platform be composed visually, with the structure and behavior that make a form feel considered rather than improvised.

The starting point is layout. A form can be split into tabs, grouped into labeled sections, and laid out in one, two, or three columns depending on how dense it needs to be. The builder supports nested groups for cases where a section itself has meaningful subdivisions. Every field gets a label, an optional placeholder, and an optional description that appears inline. The result is a form that organizes itself the way a user's attention wants to flow, rather than the way the underlying type happens to have accumulated fields.

The feature that usually surprises people is conditional visibility. A field appears only when it should — a VAT number field when the customer type is Business, a reason for cancellation field when the status is set to Cancelled, a preferred contact time field when the preferred channel is Phone. Conditions are expressions against the form's own state, written in the same inline expression language used elsewhere in the platform. The form reacts as the user types, and the same conditions are re-checked on save, so the server never accepts input that the form wouldn't allow.

Validation follows the same declarative spirit. You can attach rules — minimum, maximum, length, regular expression — directly to a field in the builder. Rules are evaluated client-side for immediate feedback and again on the server, so a malicious or outdated client can't slip past them. Custom error messages are part of the rule, which means the error the user sees is the one the form designer wrote, not a generic "invalid input." Input masks prevent whole categories of mistakes before they happen — phone numbers in the right shape, reference codes in the expected format, dates entered in an unambiguous way.

Per-role field permissions are the next layer. A single form can show different fields to different people. Managers see the salary column; other roles see the record without it, or see it read-only. The salesperson sees the internal notes field, but the customer portal doesn't. Sensitive fields can be hidden entirely, or shown with redaction, and those decisions are configuration choices rather than separate forms to maintain. One type, one form definition, many roles — and the right view appears to each user without branching in the underlying implementation.

Defaults close another common gap. A default can be a simple constant or a live expression. Due date defaults to today plus thirty days. Assigned user defaults to the current user. Organization defaults to the organization of the creator's team. These are the tiny conveniences that separate a form people tolerate from a form people enjoy using, and they're trivial to add through the builder. The same mechanism distinguishes add mode from edit mode, so a field can appear only when a record is being created, or only after it exists.

A small ergonomic detail worth mentioning: a horizontal layout option places labels beside inputs rather than above them, which suits dense back-office screens. And because every form is defined against a type from the object model, any change you make to a property — a new option, a stricter validation, a changed display widget — propagates into the form automatically. You describe the field once; the form stays honest about what that field is.

When the built-in builder isn't enough — when a form needs to look like a finished page with images, related lists, custom sections, or branded layout — the canvas page builder takes over, and the two integrate cleanly. Most forms don't need to go that far, though. A well-built form, assembled visually with the tools above, tends to be the one that ages best and requires the least maintenance. It's where the property library and the expression language meet, and it's where the time spent on the data model starts paying users back.