Form inputs

value and onChange always go together

Key points

  • Keep an input's value in state. Show it with value={name} and update it with onChange (a controlled component)
  • value and onChange go together. Without onChange, you can't type anything
  • For checkboxes, use checked instead of value, and e.target.checked instead of e.target.value

Try it

import { useState } from "react"

export default function App() {
  const [name, setName] = useState("")
  const [agreed, setAgreed] = useState(false)

  return (
    <div style={{ padding: 16, display: "grid", gap: 12 }}>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Name"
      />
      <label>
        <input
          type="checkbox"
          checked={agreed}
          onChange={(e) => setAgreed(e.target.checked)}
        />
        I agree to the terms of use
      </label>
      <button disabled={!name || !agreed}>Submit</button>
      <p>Typing: {name}</p>
    </div>
  )
}
  1. Delete the onChange line and confirm you can no longer type
  2. Add an email input (create one more state)
  3. When the name is empty, show "Please enter your name" in red (hint: &&)

Common pitfalls

Writing value but forgetting onChange
value={name} says "display the state's value", so if onChange doesn't update the state, whatever you type snaps back.
disabled={!agreed} means "can't press it unless you've agreed"
! flips the value. Reading it out loud in plain words makes it easy to understand. Join multiple conditions with || (if any one isn't met, the button can't be pressed).