Quick answer: React handles user interaction by attaching handler functions to JSX attributes: <button onClick={handleClick}>. Names are camelCase (onClick, onChange, onSubmit), handlers receive a synthetic event object, and onChange fires on every keystroke — React inputs are “controlled” when their value comes from state. This guide covers the handlers you will use daily, the controlled-form pattern, and submission with validation.

The event handlers you will use daily

HandlerFires whenTypical use
onClickElement clickedButtons, links-as-buttons, tabs
onChangeInput value changes (per keystroke)Text inputs, selects, textareas
onSubmitForm submitted (Enter or button)Any form
onBlurElement loses focusField-level validation after leaving
onKeyDownKey pressedEnter-to-submit, Escape-to-close

Pass the function itself, not a call: onClick={handleClick} — writing onClick={handleClick()} fires during render (infinite loop territory). For inline arguments, wrap in an arrow: onClick={() => remove(id)}.

Controlled inputs: the React form pattern

A controlled input’s value lives in state, and onChange writes every keystroke back:

function ContactForm() {
  const [form, setForm] = useState({ name: '', message: '' });
  const [sent, setSent] = useState(false);

  async function handleSubmit(e) {
    e.preventDefault(); // stop the browser's full-page reload
    if (!form.name.trim() || form.message.length < 10) {
      alert('Name required, message needs 10+ characters.');
      return;
    }
    // ... send to your API here ...
    setSent(true);
    setForm({ name: '', message: '' });
  }

  return (
    <form onSubmit={handleSubmit}>
      {sent && <p className="ok">Message sent!</p>}
      <label>
        Name
        <input value={form.name} onChange={e => setForm({ ...form, name: e.target.value })} />
      </label>
      <label>
        Message
        <textarea value={form.message} onChange={e => setForm({ ...form, message: e.target.value })} />
      </label>
      <button type="submit">Send</button>
    </form>
  );
}

Three things worth internalizing: preventDefault() is mandatory on form submit or the page reloads like it is 2005; the single state object pattern keeps one onChange shape per field; and because state drives the value, clearing the form is just setForm with empty strings — no DOM poking.

Validation: the pragmatic order

  • Required and length checks in handleSubmit — catch mistakes before the network call.
  • onBlur per-field checks — flag an email format error when the user leaves the field, not on every keystroke.
  • Disabled submit while invalid — <button disabled={!form.name}> prevents noise; combine with a hint, never alone.
  • Server-side always — client validation is UX, not security.

Common event bugs in week one

SymptomCauseFix
Infinite re-render on clickonClick={setX(1)} — called during renderonClick={() => setX(1)}
Page reloads on submitMissing e.preventDefault()First line of every onSubmit
Input will not let you typevalue set without onChangeControlled inputs need both, or use defaultValue
Handler sees old stateStale closure over state variableUpdater form from the useState guide: setX(x => !x)

This closes the core series: setup, components and props, state, lists, and now events and forms. With these five you can build genuinely useful interfaces — the natural next steps are side effects (useEffect) and routing, which we will cover as the React category grows.

If you would rather learn this with an instructor reviewing your forms and handlers live, Ampersand Academy teaches React one-to-one, building real interfaces with you.

Frequently asked questions

How do I handle button clicks in React?

Pass a function to the onClick prop:

Why does my React page reload on form submit?

The browser performs its default submission. Call e.preventDefault() as the first line inside your onSubmit handler to stop the reload and handle the form in JavaScript.

What is a controlled input in React?

A controlled input takes its value from React state and reports every change through onChange. The state is the single source of truth, which makes clearing, validating and previewing values trivial.

When does onChange fire in React?

On every keystroke (and selection change), unlike the native change event which fires on blur. This makes React inputs immediately responsive to typing.

How do I validate a form in React?

Check values in handleSubmit before sending, flag individual fields on blur, and optionally disable the submit button while required fields are empty. Always re-validate on the server.