Debuggler LogoDebuggler
All challenges
The Stubborn InputFormsFormik
import { useState, useEffect } from "react";

export default function App() {
  const [profile, setProfile] = useState({ name: "", bio: "" });

  useEffect(() => {
    const b = document.body;
    b.style.background = "#fafafa"; b.style.margin = "0";
    return () => { b.style.background = ""; b.style.margin = ""; };
  }, []);

  const handleReset = () => {
    setProfile({ name: "Jane Doe", bio: "Software Engineer" });
  };

  return (
    <div style={styles.page}>
      <div style={styles.card}>
        <h1 style={styles.h1}>Profile Settings</h1>
        <p style={styles.sub}>Customize your public profile card below.</p>
        
        {/* 
          BUG: The ProfileInput component is a hybrid controlled/uncontrolled component.
          It accepts a 'value' prop but duplicates it into local state 'localValue'.
          When 'Reset Defaults' is clicked, the parent state updates, but the ProfileInput 
          ignores the prop change after mounting, leaving the inputs stubbornly unchanged.
          
          The fix is to make ProfileInput fully controlled by removing its local state 
          and directly using the 'value' and 'onChange' props.
        */}
        <ProfileInput
          label="Full Name"
          value={profile.name}
          onChange={(val) => setProfile(p => ({ ...p, name: val }))}
          placeholder="Enter full name"
          dataTestId="name-input"
        />

        <ProfileInput
          label="Short Bio"
          value={profile.bio}
          onChange={(val) => setProfile(p => ({ ...p, bio: val }))}
          placeholder="Enter short bio"
          dataTestId="bio-input"
        />

        <div style={styles.actions}>
          <button
            data-testid="reset-btn"
            onClick={handleReset}
            style={styles.resetBtn}
          >
            Reset to Defaults
          </button>
        </div>
      </div>
    </div>
  );
}

function ProfileInput({ label, value, onChange, placeholder, dataTestId }) {
  const [localValue, setLocalValue] = useState(value);

  const handleChange = (e) => {
    setLocalValue(e.target.value);
    onChange(e.target.value);
  };

  return (
    <div style={styles.inputGroup}>
      <label style={styles.label}>{label}</label>
      <input
        data-testid={dataTestId}
        value={localValue}
        onChange={handleChange}
        placeholder={placeholder}
        style={styles.input}
      />
    </div>
  );
}

const styles = {
  page: { display: "flex", justifyContent: "center", padding: "40px 20px", fontFamily: "system-ui, sans-serif" },
  card: { background: "#fff", borderRadius: 12, padding: "24px", width: "100%", maxWidth: 400, boxShadow: "0 4px 6px -1px rgba(0,0,0,0.1)" },
  h1: { margin: "0 0 6px", fontSize: 20, fontWeight: 600, color: "#111827" },
  sub: { margin: "0 0 20px", fontSize: 14, color: "#6B7280" },
  inputGroup: { display: "flex", flexDirection: "column", gap: 6, marginBottom: 16 },
  label: { fontSize: 13, fontWeight: 500, color: "#374151" },
  input: { width: "100%", boxSizing: "border-box", padding: "10px 12px", fontSize: 14, borderRadius: 6, border: "1px solid #D1D5DB", outline: "none" },
  actions: { display: "flex", justifyContent: "flex-end", marginTop: 8 },
  resetBtn: { background: "#fff", border: "1px solid #D1D5DB", color: "#374151", padding: "8px 16px", borderRadius: 6, fontSize: 14, cursor: "pointer", fontWeight: 500 }
};

Type into the custom input fields. Try clicking the 'Reset Defaults' button. Notice that while the parent state is successfully reset, the input fields remain stubbornly stuck showing your custom text. Fix the controlled input sync.

After you fix it

  • Clicking 'Reset Defaults' should instantly reset both Full Name and Bio input fields to their initial values.
  • The child input elements should be fully controlled by the parent component's state.

Click "Run checks" to verify your solution.