[{"data":1,"prerenderedAt":108},["ShallowReactive",2],{"qa-\u002Freact\u002Fstate-and-data-flow\u002Fcontrolled-vs-uncontrolled":3},{"page":4,"siblings":92,"blog":105},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":20,"order":21,"path":22,"questions":23,"questionsCount":82,"related":83,"seo":84,"seoDescription":85,"stem":86,"subtopic":87,"topic":88,"topicSlug":89,"updated":90,"__hash__":91},"qa\u002Freact\u002Fstate-and-data-flow\u002Fcontrolled-vs-uncontrolled.md","Controlled Vs Uncontrolled",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","React","react",{"subtopicSlug":19},"controlled-vs-uncontrolled",true,3,"\u002Freact\u002Fstate-and-data-flow\u002Fcontrolled-vs-uncontrolled",[24,29,33,37,41,45,49,53,57,61,65,69,73,78],{"id":25,"difficulty":26,"q":27,"a":28},"controlled-what","easy","What is a controlled component in React?","A **controlled component** is one where React state is the **single\nsource of truth** for the input's value. The displayed value comes from\nstate; every change must go through state via an `onChange` handler.\n\n```jsx\nfunction ControlledInput() {\n  const [value, setValue] = useState('')\n\n  return (\n    \u003Cinput\n      value={value}                         \u002F\u002F state drives the DOM\n      onChange={e => setValue(e.target.value)} \u002F\u002F DOM change updates state\n    \u002F>\n  )\n}\n```\n\nReact keeps the DOM perfectly in sync with state — you can read,\nvalidate, or transform every keystroke before it appears.\n\n**Rule of thumb:** If you need to validate, transform, or react to every\nchange as the user types, use a controlled component.\n",{"id":30,"difficulty":26,"q":31,"a":32},"uncontrolled-what","What is an uncontrolled component in React?","An **uncontrolled component** lets the DOM manage its own state. React\ndoes not drive the input's value — you only read it when you need it\n(typically on submit) using a `ref`.\n\n```jsx\nfunction UncontrolledForm() {\n  const inputRef = useRef(null)\n\n  function handleSubmit(e) {\n    e.preventDefault()\n    console.log(inputRef.current.value)   \u002F\u002F read on demand\n  }\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003Cinput ref={inputRef} defaultValue=\"initial\" \u002F>\n      \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\nBecause there is no React state involved, uncontrolled inputs are\nsimpler to set up but offer less control over intermediate values.\n\n**Rule of thumb:** Use uncontrolled components for simple forms where\nyou only care about the final submitted value, not intermediate input.\n",{"id":34,"difficulty":26,"q":35,"a":36},"controlled-vs-uncontrolled-key-diff","What is the key difference between the `value` and `defaultValue` props on an input?","| Prop | Type | Behaviour |\n|---|---|---|\n| `value` | Controlled | React always overrides the DOM value; component is controlled |\n| `defaultValue` | Uncontrolled | Sets the initial value once; DOM manages value after that |\n\n```jsx\n\u002F\u002F Controlled — React owns the value at all times\n\u003Cinput value={stateValue} onChange={e => setState(e.target.value)} \u002F>\n\n\u002F\u002F Uncontrolled — React only sets the initial value\n\u003Cinput defaultValue=\"hello\" ref={inputRef} \u002F>\n```\n\nMixing `value` without `onChange` makes the input read-only from the\nuser's perspective (React prevents edits). React will warn you.\n\n**Rule of thumb:** Use `value` when React should own the value;\nuse `defaultValue` when the DOM should own it after mount.\n",{"id":38,"difficulty":26,"q":39,"a":40},"controlled-when-to-use","When should you prefer a controlled component over an uncontrolled one?","Prefer controlled components when you need:\n- **Instant validation** (highlight errors as the user types)\n- **Conditional UI** based on current field value\n- **Dynamic constraints** (disable a button until all fields are valid)\n- **Programmatic value changes** (auto-fill, clear on reset)\n\n```jsx\nfunction EmailField() {\n  const [email, setEmail] = useState('')\n  const isValid = email.includes('@')\n\n  return (\n    \u003C>\n      \u003Cinput\n        value={email}\n        onChange={e => setEmail(e.target.value)}\n        className={isValid ? 'valid' : 'invalid'}\n      \u002F>\n      \u003Cbutton disabled={!isValid}>Subscribe\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** Most production forms use controlled inputs because\nthey provide the feedback loop needed for good UX.\n",{"id":42,"difficulty":26,"q":43,"a":44},"uncontrolled-when-to-use","When is an uncontrolled component a better choice?","Uncontrolled inputs are simpler when:\n- You only need the value at submit time (e.g. a basic search box)\n- Integrating with **non-React libraries** that manage their own DOM\n- Handling **file inputs** (`\u003Cinput type=\"file\">` is always uncontrolled\n  because the browser controls the file path for security)\n- Rapid prototyping where wiring up state would slow you down\n\n```jsx\n\u002F\u002F File inputs are always uncontrolled\nfunction FileUpload() {\n  const fileRef = useRef(null)\n\n  function handleUpload() {\n    const file = fileRef.current.files[0]\n    upload(file)\n  }\n\n  return (\n    \u003C>\n      \u003Cinput type=\"file\" ref={fileRef} \u002F>\n      \u003Cbutton onClick={handleUpload}>Upload\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** `\u003Cinput type=\"file\">` is always uncontrolled; for\neverything else, default to controlled unless simplicity wins.\n",{"id":46,"difficulty":26,"q":47,"a":48},"controlled-warning-read-only","What warning does React show if you set `value` without an `onChange` handler?","React logs:\n> *\"You provided a `value` prop to a form field without an `onChange`\n> handler. This will render a read-only field.\"*\n\nThe input is effectively frozen — the user types but the DOM value is\nalways reset to `value` by React on every render.\n\n```jsx\n\u002F\u002F ❌ Read-only — React overrides every keystroke\n\u003Cinput value=\"fixed\" \u002F>\n\n\u002F\u002F ✅ Controlled with handler\n\u003Cinput value={state} onChange={e => setState(e.target.value)} \u002F>\n\n\u002F\u002F ✅ Or explicitly read-only with readOnly\n\u003Cinput value=\"fixed\" readOnly \u002F>\n```\n\n**Rule of thumb:** If you pass `value`, you must also pass `onChange`\n(or `readOnly` if intentionally read-only).\n",{"id":50,"difficulty":14,"q":51,"a":52},"controlled-null-value","What happens if you pass `null` or `undefined` as the `value` prop?","Passing `null` or `undefined` makes the input **uncontrolled** — React\ntreats it the same as omitting `value`. If you later switch back to a\nreal value, React warns that you're changing a component from\nuncontrolled to controlled.\n\n```jsx\n\u002F\u002F ❌ Starts uncontrolled (value is null initially)\nconst [text, setText] = useState(null)\n\u003Cinput value={text} onChange={e => setText(e.target.value)} \u002F>\n\u002F\u002F React: \"changing an uncontrolled input to be controlled\"\n\n\u002F\u002F ✅ Always start controlled with an empty string\nconst [text, setText] = useState('')\n\u003Cinput value={text} onChange={e => setText(e.target.value)} \u002F>\n```\n\n**Rule of thumb:** Initialise controlled state with an empty string\n(`''`) rather than `null` or `undefined`.\n",{"id":54,"difficulty":26,"q":55,"a":56},"controlled-textarea-select","How do controlled and uncontrolled patterns apply to textarea and select elements?","The same `value`\u002F`defaultValue` pattern applies to `\u003Ctextarea>` and\n`\u003Cselect>`. React normalises them so they behave consistently.\n\n```jsx\n\u002F\u002F Controlled textarea\n\u003Ctextarea value={text} onChange={e => setText(e.target.value)} \u002F>\n\n\u002F\u002F Controlled select\n\u003Cselect value={selected} onChange={e => setSelected(e.target.value)}>\n  \u003Coption value=\"a\">Option A\u003C\u002Foption>\n  \u003Coption value=\"b\">Option B\u003C\u002Foption>\n\u003C\u002Fselect>\n\n\u002F\u002F Uncontrolled select with initial selection\n\u003Cselect defaultValue=\"b\" ref={selectRef}>\n  \u003Coption value=\"a\">Option A\u003C\u002Foption>\n  \u003Coption value=\"b\">Option B\u003C\u002Foption>\n\u003C\u002Fselect>\n```\n\n**Rule of thumb:** Treat `\u003Ctextarea>` and `\u003Cselect>` exactly like\n`\u003Cinput>` — use `value` for controlled, `defaultValue` for uncontrolled.\n",{"id":58,"difficulty":26,"q":59,"a":60},"controlled-ref-reading","Can you read an uncontrolled input's value without a ref?","Technically yes — via the native form submit event's\n`e.target.elements` map — but `ref` is the idiomatic React approach.\n\n```jsx\n\u002F\u002F Using ref (recommended)\nconst inputRef = useRef(null)\n\u003Cinput ref={inputRef} \u002F>\n\u002F\u002F Read: inputRef.current.value\n\n\u002F\u002F Using the form submit event (also works, no ref needed)\nfunction handleSubmit(e) {\n  e.preventDefault()\n  const value = e.target.elements.username.value\n}\n\u003Cform onSubmit={handleSubmit}>\n  \u003Cinput name=\"username\" \u002F>\n\u003C\u002Fform>\n```\n\nThe `name`-based approach is fine for very simple forms and mirrors\ntraditional HTML form handling.\n\n**Rule of thumb:** Use `ref` for programmatic access during the\ncomponent's lifetime; use `e.target.elements` for one-shot submit\nreading.\n",{"id":62,"difficulty":14,"q":63,"a":64},"controlled-mixed-form","Can a single form have both controlled and uncontrolled inputs?","Technically yes, but it's an anti-pattern. Mixing paradigms makes the\ncode harder to reason about and breaks the \"single source of truth\"\nprinciple.\n\n```jsx\n\u002F\u002F ❌ Confusing mix\nfunction Form() {\n  const [email, setEmail] = useState('')   \u002F\u002F controlled\n  const phoneRef = useRef(null)            \u002F\u002F uncontrolled\n\n  function handleSubmit() {\n    const data = { email, phone: phoneRef.current.value }\n    \u002F\u002F collecting values from two different sources\n  }\n}\n\n\u002F\u002F ✅ Consistent — all controlled or all via refs\n```\n\nIf you choose controlled, keep all fields controlled. If you use a\nlibrary like React Hook Form it manages uncontrolled inputs uniformly.\n\n**Rule of thumb:** Pick one pattern per form and stick to it.\n",{"id":66,"difficulty":14,"q":67,"a":68},"controlled-react-hook-form","How does React Hook Form differ from the traditional controlled component pattern?","React Hook Form uses **uncontrolled inputs by default** (via `ref`),\nsubscribing to change events without storing every keystroke in React\nstate. This results in **fewer re-renders** — the component only\nre-renders when validation state changes or on submit.\n\n```jsx\nimport { useForm } from 'react-hook-form'\n\nfunction SignupForm() {\n  const { register, handleSubmit, formState: { errors } } = useForm()\n\n  return (\n    \u003Cform onSubmit={handleSubmit(data => console.log(data))}>\n      {\u002F* register wires up ref + onChange internally *\u002F}\n      \u003Cinput {...register('email', { required: true })} \u002F>\n      {errors.email && \u003Cspan>Email required\u003C\u002Fspan>}\n      \u003Cbutton type=\"submit\">Sign up\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\nFor controlled integration use the `Controller` component or\n`useController` hook.\n\n**Rule of thumb:** React Hook Form is the pragmatic choice for\ncomplex forms — it gives controlled-like DX with uncontrolled\nperformance.\n",{"id":70,"difficulty":14,"q":71,"a":72},"controlled-reset","How do you programmatically reset a controlled form to its initial values?","Call the state setter with the original default values. Because the\ninput values are driven by React state, setting state is all you need.\n\n```jsx\nconst INITIAL = { name: '', email: '' }\n\nfunction ProfileForm() {\n  const [form, setForm] = useState(INITIAL)\n\n  function reset() {\n    setForm(INITIAL)    \u002F\u002F inputs snap back to empty\n  }\n\n  return (\n    \u003Cform>\n      \u003Cinput value={form.name}  onChange={e => setForm(p => ({ ...p, name: e.target.value }))} \u002F>\n      \u003Cinput value={form.email} onChange={e => setForm(p => ({ ...p, email: e.target.value }))} \u002F>\n      \u003Cbutton type=\"button\" onClick={reset}>Reset\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\nFor uncontrolled forms you need to call `inputRef.current.value = ''`\nfor each field manually, which is why controlled inputs are easier to\nreset programmatically.\n\n**Rule of thumb:** Controlled components make reset trivial — just\nrestore state. Uncontrolled forms require manual DOM manipulation.\n",{"id":74,"difficulty":75,"q":76,"a":77},"controlled-dynamic-fields","hard","How do you manage a dynamic list of controlled input fields?","Store the list in state as an array. Each field reads from its array\nslot and writes back using its index or a stable id.\n\n```jsx\nfunction TagsInput() {\n  const [tags, setTags] = useState(['react', 'hooks'])\n\n  function handleChange(index, value) {\n    setTags(prev => prev.map((t, i) => i === index ? value : t))\n  }\n\n  function addTag() {\n    setTags(prev => [...prev, ''])\n  }\n\n  function removeTag(index) {\n    setTags(prev => prev.filter((_, i) => i !== index))\n  }\n\n  return (\n    \u003C>\n      {tags.map((tag, i) => (\n        \u003Cdiv key={i}>\n          \u003Cinput value={tag} onChange={e => handleChange(i, e.target.value)} \u002F>\n          \u003Cbutton onClick={() => removeTag(i)}>✕\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      ))}\n      \u003Cbutton onClick={addTag}>+ Add\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** Use stable ids rather than array indices as `key`\nwhen items can be reordered to avoid React losing focus state.\n",{"id":79,"difficulty":26,"q":80,"a":81},"controlled-vs-uncontrolled-interview-summary","How would you summarise the controlled vs. uncontrolled tradeoff in one sentence?","**Controlled** components give React full authority over the input value\nat the cost of wiring up `onChange` state; **uncontrolled** components\nlet the DOM own the value and are simpler to set up but harder to\nintegrate with validation and dynamic UI.\n\n```\nControlled  → React state is truth → more wiring, more power\nUncontrolled → DOM is truth         → less wiring, less control\n```\n\nThe React docs historically recommended controlled components for most\ncases; today, form libraries (React Hook Form) offer a third path that\nis uncontrolled under the hood but feels controlled in the API.\n\n**Rule of thumb:** Default to controlled unless performance or\nthird-party DOM libraries push you toward uncontrolled.\n",14,null,{"description":11},"React controlled vs uncontrolled components interview questions — value vs defaultValue, refs, form handling, when to use each approach.","react\u002Fstate-and-data-flow\u002Fcontrolled-vs-uncontrolled","Controlled vs Uncontrolled Components","State and Data Flow","state-and-data-flow","2026-06-24","pcInXbHq2wIIioyp57ydXhnhjx7QfGClTxyTTNAfRrI",[93,97,100,101],{"subtopic":94,"path":95,"order":96},"Lifting State Up","\u002Freact\u002Fstate-and-data-flow\u002Flifting-state",1,{"subtopic":98,"path":99,"order":12},"Context API","\u002Freact\u002Fstate-and-data-flow\u002Fcontext-api",{"subtopic":87,"path":22,"order":21},{"subtopic":102,"path":103,"order":104},"Prop Drilling and Composition","\u002Freact\u002Fstate-and-data-flow\u002Fprop-drilling-composition",4,{"path":106,"title":107},"\u002Fblog\u002Freact-controlled-vs-uncontrolled-guide","Controlled vs Uncontrolled Components in React — A Complete Guide",1782244100917]