React Events

React lets you respond to user interactions like clicks, typing, and form submissions by attaching event handler functions directly to JSX elements.

Wiring Up onClick

In React, you attach event handlers to elements using camelCase attributes such as onClick, onChange, and onSubmit. Unlike HTML's string-based onclick="..." attributes, React expects an actual JavaScript function — a reference, not a function call. Passing myFunction() instead of myFunction runs the function immediately during render instead of waiting for the click.

A Button That Counts Clicks

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

export default Counter;

Passing Arguments to Handlers

Sometimes a handler needs extra information, like which item in a list was clicked. Since onClick expects a function reference, you can't write onClick={handleDelete(id)} directly — that calls handleDelete immediately during render. Instead, wrap the call in an inline arrow function, which React will invoke only when the event actually fires.

Deleting an Item by Id

import { useState } from 'react';

function TodoItem({ id, text, onDelete }) {
  return (
    <li>
      {text}
      <button onClick={() => onDelete(id)}>Delete</button>
    </li>
  );
}

function TodoList({ items, onDelete }) {
  return (
    <ul>
      {items.map((item) => (
        <TodoItem key={item.id} {...item} onDelete={onDelete} />
      ))}
    </ul>
  );
}

function App() {
  const [items, setItems] = useState([
    { id: 1, text: 'Buy milk' },
    { id: 2, text: 'Walk the dog' },
    { id: 3, text: 'Write React lesson' },
  ]);

  function handleDelete(id) {
    setItems((current) => current.filter((item) => item.id !== id));
  }

  return <TodoList items={items} onDelete={handleDelete} />;
}

export default App;
Note: A common beginner mistake is writing onClick={handleClick()} instead of onClick={handleClick}. The first form calls handleClick during rendering and hands React whatever it returns (often undefined), so the click is never actually handled.

Reading the Event Object

Every handler receives a SyntheticEvent as its first argument — a wrapper React builds around the browser's native event so it behaves consistently across browsers. You can read properties like event.target.value, call event.preventDefault(), or stop propagation with event.stopPropagation(), exactly as you would with a native DOM event.

Event PropFires OnTypical Use
onClickMouse clickButtons, links, toggles
onChangeInput value changesControlled form fields
onSubmitForm submissionValidating and sending form data
onMouseEnterPointer enters an elementHover cards, tooltips
onKeyDownA key is pressedKeyboard shortcuts, Enter-to-submit

Combining an Event and a Value

import { useState } from 'react';

function SearchBox({ onSearch }) {
  function handleChange(event) {
    onSearch(event.target.value);
  }

  return (
    <input
      type="text"
      placeholder="Search..."
      onChange={handleChange}
    />
  );
}

function App() {
  const [query, setQuery] = useState('');

  return (
    <div>
      <SearchBox onSearch={setQuery} />
      <p>Searching for: {query}</p>
    </div>
  );
}

export default App;
  • Name handlers with a handle prefix, like handleClick or handleSubmit, so their purpose is obvious at a glance.
  • Extract inline arrow functions into named functions once the logic grows past a single line.
  • Never call the handler directly in JSX — pass the reference, or wrap it in an arrow function if arguments are needed.
  • Destructure only the event fields you need (event.target.value) rather than storing the whole event object in state.

Exercise: React Events

How are event handler attribute names written in JSX, such as for a click event?