Q163: React Forms, Controlled, Uncontrolled and Server Actions
What Interviewers Want To Evaluate
This question checks whether you can design form systems that are correct, accessible, performant, and resilient. Interviewers want controlled and uncontrolled trade-offs, validation, error display, async submission, progressive enhancement, field arrays, file inputs, optimistic UI, and Next.js Server Action boundaries.
Senior answers should treat forms as product workflows, not just input handlers.
Short Interview Answer
Controlled forms keep input values in React state, which makes validation, formatting, conditional UI, and cross-field logic straightforward but can cause rerenders in large forms. Uncontrolled forms let the DOM hold the current value and read it through refs or FormData, which can be simpler and faster for large or mostly native forms. In Next.js, forms can submit to Server Actions for mutations while client components handle interactive validation and optimistic UI when needed.
Detailed Interview Answer
Controlled input:
function NameField() {
const [name, setName] = useState("");
return (
<input
value={name}
onChange={(event) => setName(event.target.value)}
/>
);
}
React state is the source of truth.
Uncontrolled input:
function NameForm() {
const inputRef = useRef(null);
function submit() {
console.log(inputRef.current.value);
}
return <input ref={inputRef} defaultValue="" />;
}
The DOM is the source of truth until you read from it.
Controlled Form Strengths
Controlled forms are useful when the UI depends on each keystroke.
live validation
input masking
dependent fields
computed previews
conditional sections
autosave
dirty-state tracking
custom widgets
They make state explicit and testable.
Controlled Form Costs
Every keystroke schedules React work.
For small forms this is fine.
For large forms, table editors, or deeply nested custom controls, the cost can become visible.
Common mitigations:
split fields into memoized components
keep field state close to each field
avoid global context updates per keystroke
defer expensive derived work
validate on blur or submit where acceptable
use form libraries with granular subscriptions
Uncontrolled Form Strengths
Uncontrolled forms work well when native browser behavior is enough.
simple login forms
search forms
large forms submitted as FormData
file inputs
native validation flows
progressively enhanced forms
They reduce React state churn and preserve browser semantics.
FormData
Native form submission naturally creates FormData.
function onSubmit(event) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const email = formData.get("email");
}
This is especially useful when sending data to server mutations.
Server Actions
In Next.js App Router, a form can submit to a Server Action.
async function createUser(formData: FormData) {
"use server";
const email = String(formData.get("email") ?? "");
await saveUser({ email });
}
export function UserForm() {
return (
<form action={createUser}>
<input name="email" type="email" required />
<button type="submit">Save</button>
</form>
);
}
This keeps mutation logic on the server and supports progressive enhancement.
Validation Layers
Validation should happen at multiple layers.
HTML constraints for basic browser support
client validation for fast feedback
server validation for authority
runtime schema validation at trust boundaries
database constraints for final integrity
Client validation improves UX. Server validation protects correctness.
Error UX
Good form errors are specific, accessible, and recoverable.
connect error text with aria-describedby
show errors near fields and summary when useful
preserve user input after failure
focus the first meaningful error after submit
avoid clearing data on retry
distinguish validation, network, and permission errors
Error copy should tell the user what to do next.
Field Arrays
Dynamic fields need stable keys and stable names.
do not use array index when rows can reorder
preserve field identity across insert and delete
validate each row independently
handle duplicate and empty row cases
support keyboard movement and removal
This is where form libraries often help.
File Inputs
File inputs are inherently uncontrolled.
You cannot safely set their value from React state.
Design file workflows around selected files, preview state, upload progress, cancellation, retry, and server-side validation.
Optimistic UI
Optimistic UI is useful when the expected mutation usually succeeds.
add item immediately
disable duplicate submit
show pending state
rollback or reconcile on failure
announce status accessibly
Optimism should not hide server authority.
Common Mistakes
A common mistake is validating only on the client.
Another mistake is putting every field update into one global context.
Another mistake is showing errors without connecting them to inputs.
Another mistake is using controlled state for file inputs.
Another mistake is losing user input after a failed submit.
Senior Trade-Offs
Controlled forms give maximum UI control. Uncontrolled forms preserve native behavior and reduce React work.
The best architecture often mixes both: controlled custom widgets, uncontrolled native fields, server validation, and a form library when complexity justifies it.
Code or Design Example
export function SearchForm() {
return (
<form action="/search">
<label htmlFor="query">Search</label>
<input id="query" name="q" type="search" />
<button type="submit">Search</button>
</form>
);
}
This simple form does not need controlled state.
Debugging Workflow
When a form feels broken:
check source of truth
inspect rerenders during typing
test keyboard and screen reader flow
test failed submission recovery
verify server validation
check duplicate submit behavior
test slow network and timeout paths
test mobile input modes
Interview Framing
Start with controlled vs uncontrolled. Then discuss validation layers, accessibility, async submission, Server Actions, performance, and recovery.
Revision Notes
Forms are state machines with user trust attached. Treat them as workflows.
Key Takeaways
Choose the form model by interaction needs. Do not make every input controlled by habit.
Follow-Up Questions
- What is a controlled input?
- What is an uncontrolled input?
- When are controlled forms useful?
- When are uncontrolled forms better?
- Why is server validation required?
- How do Server Actions change form design?
- How should form errors be made accessible?
- Why are file inputs special?
- How do field arrays preserve identity?
- When should a form library be used?
How I Would Answer This In A Real Interview
I would say controlled forms are best when React needs to own each change, while uncontrolled forms are better for simple or native workflows. I would then cover validation layers, accessible error recovery, Server Actions for mutations, and performance choices for large forms.