Determine the right form problem before writing code

A framework-agnostic method for separating validation, state ownership, synchronization, and workflow problems before a form becomes expensive to change.

Why this matters

A SAP Business One Business Partner editor can fail even when every input works. A user changes CreditLimit, an autosave overwrites a colleague’s change, the page shows success, and the record still cannot be submitted because its CardCode is invalid. That is not primarily an input-component problem.

A form is a temporary workspace for a business transaction. Before choosing React Hook Form, TanStack Form, Angular forms, or plain state, identify the transaction, its owner, and its rules. The same reasoning applies to every frontend framework.

Who this is for

Mid-level through staff-level frontend engineers, technical leads, and architects designing or reviewing CRUD workflows in any frontend framework.

Classify the form problemA proposed form change is classified as a data rule, state ownership, UI synchronization, or business workflow problem before implementation begins. Yes No No Yes Yes No Form issue Data rule? Validation One owner? Ownership Views disagree? Synchronization Workflow
Classify the form problem

Decision checklist

Before designing fields, answer these questions in writing:

  1. What business outcome is being changed? “Save Business Partner” is vague; “change CreditLimit, EmailAddress, and one Bill-to BPAddresses row for CardCode C20000” is a transaction.
  2. What is the commit boundary? Can a Business Partner’s credit setting save independently of a Business Partner Group master-data change? Usually yes.
  3. Who owns draft state? Usually one form controller owns it. A reusable Business Partner Group selector owns presentation, not the parent transaction.
  4. Which rules can run locally, and which require current server data? A required CardName, EmailAddress, or BPAddresses[].AddressName differs from “this CardCode is already assigned.”
  5. What happens on save, failure, discard, and concurrent change? These are states, not afterthoughts.
  6. Is the user editing one transaction or several? A wizard may be one transaction; two independent panels should not share a fake parent form.

If the team cannot name the transaction boundary, do not start with a form library. Resolve the product workflow first.

Common anti-patterns

PatternWhy it looks reasonableLong-term consequenceBetter boundary
Parent knows every child fieldIt centralizes SaveParent changes for every section changeParent owns submit orchestration; sections expose a focused value contract
Child writes parent state directlyIt removes a callbackHidden coupling and impossible reuseChild emits an intent or binds to a scoped field API
Duplicate draft stateLocal state feels convenientConflicting values and reset bugsOne draft source of truth
useEffect copies dirty stateIt appears to keep values currentRaces, loops, and lost editsDerive UI from form state; reset only at explicit lifecycle boundaries
Rules scattered across componentsEach field can “own” its checkInconsistent messages and missed server checksPut rules beside the domain shape and orchestrate their timing centrally
API call inside reusable inputThe input has the valueUI primitives acquire business dependenciesKeep inputs presentational; inject async behavior from the form feature
One giant form for unrelated workOne Save button seems simplerA small change blocks unrelated workSplit independent transactions; coordinate only when the business requires it
Separate forms for one orderSections were built by different teamsPartial saves and cross-section invalidityOne transaction owner with composable sections

A useful distinction: data rules versus workflow rules

CreditLimit cannot be negative” is a data rule. “Raising CreditLimit above an approval threshold needs manager approval” is a workflow rule. The first should make the draft invalid. The second may be valid data that follows a different submit path. Treating both as red field errors makes the UI misleading.

Validation is a lifecycle, not a function

Validation answers whether a proposed value is acceptable at a particular boundary. Its timing changes the user experience and the cost of a request.

ModeRun whenBest forDo not use as the only check when
On changeInput changesCheap format checks after a field has been touchedThe rule requires a network call or interrupts typing
On blurUser leaves a fieldAvailability, normalization, focused feedbackThe user can submit without visiting the field
On submitCommit is requestedComplete transaction validationFeedback must guide the user earlier
AsyncExternal data is neededUniqueness, eligibility, current pricingA stale response could overwrite a newer value
Cross-fieldRelated values changeDate ranges, totals, conditional requirementsFields are actually separate transactions
Section-levelA user completes a stepWizard progressionThe final transaction has broader invariants
ServerEvery writeAuthorization, freshness, authoritative constraintsIt is used to replace basic client guidance

Client validation improves correction speed. Server validation protects the transaction. Neither is sufficient alone.

Save validation flowA user changes a field, receives local feedback, may receive asynchronous feedback on blur, and submits to the server which returns the authoritative result. Change value Local check Leave field Check value Valid or error Save Submit draft Saved or errors User Form draft Availability API Save API
Save validation flow

On server failure, retain the draft, map field-specific errors to their fields, show a form-level error for transaction failures, and restore the Save action once the request finishes. Do not show success until the server has accepted the transaction. Discard should return to the last acknowledged snapshot, not whatever values happened to be loaded first.

Incremental validation: validate the smallest affected scope

For a Business Partner maintenance screen with 500 editable rows, validating every row on each keystroke wastes work and makes unrelated errors jump into view. Validate the changed field first, then its dependent rules: changing GroupCode may revalidate CardType compatibility, but not a read-only CurrentAccountBalance.

This is appropriate when dependencies are explicit and validation is pure. Use a full validation on submit anyway. Prefer broader validation when a rule depends on global derived state, permissions, or a server snapshot that may have changed. Incremental validation is an optimization; it must not alter what a valid submitted transaction means.

What good validation looks like

At the field level, a message names the problem and the correction: “Enter a tax ID with 10 digits,” not “Invalid.” It is attached accessibly to the field and does not appear before the user has a reasonable chance to act.

At the form level, rules have a stable home, validation status is observable, and submit focuses the first actionable error. A section should be able to report its validity without owning the whole transaction.

At the application level, the client and server share compatible rule definitions or contracts, error codes are observable, permissions are enforced on the server, and teams can explain the source of truth. Measure validation failures by rule and endpoint; repeated failures often reveal a product or data-quality problem, not careless users.

Key takeaways

  • Start with the business transaction, then choose the form architecture.
  • Keep one authoritative draft per transaction; derive UI rather than synchronizing copies.
  • Match validation timing to cost, dependency, and user intent.
  • Validate incrementally for feedback, then validate the complete transaction before commit.
  • Keep server validation authoritative and preserve the user’s draft on failure.

Conclusion

The first architectural decision is not which hook to call. It is whether the screen represents one transaction, who owns its draft, and when the system is allowed to accept it. With those answers, a form library becomes an implementation tool instead of the place where business design accidentally happens.

Sources

  1. W3C: Web Content Accessibility Guidelines, input assistance
  2. Nielsen Norman Group: Error-message guidelines
  3. SAP Business One: BusinessPartners object members