DeployU
Interviews / Frontend Engineering / This form uses an uncontrolled input. Refactor it to be a controlled component.

Questions

This form uses an uncontrolled input. Refactor it to be a controlled component.

refactoring Forms & Input Interactive Quiz Code Examples

A developer has built a simple login form with an input field for the username and a submit button. They’ve implemented the username input as an uncontrolled component, meaning its value is managed by the DOM itself, and they access it using a ref only when the form is submitted.

Now, they want to add two new features:

  1. Real-time validation: Display an error message if the username input is empty.
  2. Dynamic button state: Disable the submit button if the username input is empty.

They are struggling to implement these features effectively because they can’t easily get the input’s value in real-time.

You’ve been given the LoginForm component. Your task is to refactor the username input from an uncontrolled component to a controlled component.

After refactoring, implement the real-time validation and dynamic button state:

  • Show an error message “Username cannot be empty” if the input is empty.
  • Disable the “Submit” button if the input is empty.
Your Code
import React, { useRef } from 'react';

export default function LoginForm() {
  const usernameInputRef = useRef(null);

  const handleSubmit = (event) => {
    event.preventDefault();
    const username = usernameInputRef.current.value;
    if (username.trim() === '') {
      alert('Username cannot be empty!');
      return;
    }
    alert(`Submitting username: ${username}`);
    // In a real app, you'd send this to an API
  };

  return (
    <form onSubmit={handleSubmit} style={{ padding: '20px', border: '1px solid #ccc' }}>
      <h2>Login</h2>
      <label>
        Username:
        {/* THE BUG: This is an uncontrolled input.
            Its value is managed by the DOM, not React state. */}
        <input type="text" ref={usernameInputRef} />
      </label>
      {/* No real-time validation or dynamic button state */}
      <button type="submit" style={{ marginLeft: '10px' }}>
        Submit
      </button>
    </form>
  );
}
Click "Run Code" to see output...
Click "Run Code" to see test results...
How Different Experience Levels Approach This
Junior Engineer
Surface Level

import React, { useRef } from 'react'; export default function LoginForm() { const usernameInputRef = useRef(null); const handleSubmit = (event) => { event.preventDefault(); const username = usernameInputRef.current.value; if (username.trim() === '') { alert('Username cannot be empty!'); return; } alert(`Submitting username: ${username}`); // In a real app, you'd send this to an API }; return ( <form onSubmit={handleSubmit} style={{ padding: '20px', border: '1px solid #ccc' }}> <h2>Login</h2> <label> Username: {/* THE BUG: This is an uncontrolled input. Its value is managed by the DOM, not React state. */} <input type="text" ref={usernameInputRef} /> </label> {/* No real-time validation or dynamic button state */} <button type="submit" style={{ marginLeft: '10px' }}> Submit </button> </form> ); }

Senior Engineer
Production Ready

import React, { useState } from 'react'; export default function LoginForm() { // FIX: Use useState to manage the input's value const [username, setUsername] = useState(''); const [error, setError] = useState(''); const handleUsernameChange = (event) => { const newValue = event.target.value; setUsername(newValue); // Real-time validation if (newValue.trim() === '') { setError('Username cannot be empty'); } else { setError(''); } }; const handleSubmit = (event) => { event.preventDefault(); if (username.trim() === '') { setError('Username cannot be empty'); // Final check on submit return; } alert(`Submitting username: ${username}`); }; // Determine if the button should be disabled const isSubmitDisabled = username.trim() === ''; return ( <form onSubmit={handleSubmit} style={{ padding: '20px', border: '1px solid #ccc' }}> <h2>Login</h2> <label> Username: {/* FIX: Bind value to state and provide onChange handler */} <input type="text" value={username} onChange={handleUsernameChange} /> </label> {/* Display real-time error message */} {error && <p style={{ color: 'red', fontSize: '0.8em' }}>{error}</p>} <button type="submit" style={{ marginLeft: '10px' }} disabled={isSubmitDisabled}> Submit </button> </form> ); }

What Makes the Difference?
  • Context over facts: Explains when and why, not just what
  • Real examples: Provides specific use cases from production experience
  • Trade-offs: Acknowledges pros, cons, and decision factors

Practice Question

What is the primary characteristic of a controlled component in React?