How to Pass Arguments to Event Handlers in React

Pass arguments to a React event handler by wrapping the call in an arrow function. The arrow runs on the event, so data arrives at the right time.

5 min read

To pass an argument to an event handler in React, wrap the call in an arrow function inside the JSX. The arrow function runs only when the event fires, so the argument arrives at the right time instead of during render. This keeps the handler from running early while still giving it the data it needs.

Why a direct call fails

A bare call runs too early. Code between JSX braces executes during rendering, so onClick={handleClick("S")} calls the handler while the component renders and passes its return value to React. The symptom is usually a handler that runs once on mount and then never again, because there is no function left for React to call on click.

Wrap the call in an arrow function

The arrow function fixes the timing. It captures the argument and defers the call until the click.

App.jsxApp.jsx
import { useState } from "react";
function SizePicker() {
  const [size, setSize] = useState("M");
  function handlePick(value) {
    setSize(value);
  }
  return <button onClick={() => handlePick("S")}>Small</button>;
}

Clicking Small runs the arrow function, which calls handlePick with the value S. The state changes to S for the next render, so a heading that reads size would update to show the new selection. The arrow captures the value at render time, then hands it to the handler only on click.

Pass an id from a list

The most common case is a list where each button must identify its own item. The arrow function closes over the current item and passes its id. Without that captured value, every button would act on the same data or on nothing at all.

App.jsxApp.jsx
{todos.map((todo) => (
  <button key={todo.id} onClick={() => handleRemove(todo.id)}>
    {todo.text}
  </button>
))}

Each button receives its own arrow function with the matching id captured. Clicking the second button removes the second item, not the first, because each row carries the id it was rendered with.

Keep the event object

Sometimes the handler needs both the event and an argument. Forward the event as the first parameter.

App.jsxApp.jsx
<button onClick={(e) => handleRemove(e, todo.id)}>Remove</button>

The arrow function receives the event from React and passes it on, so the handler can still call methods like preventDefault on it. This pattern is common when a click must both identify an item and cancel a default action. Some teams prefer bind instead, but the arrow function reads more clearly in JSX for one or two arguments.

Common mistakes

  • Writing a bare call, which runs during render.
  • Reading the event target when the item id is already in the closure.
  • Passing arguments through bind when an arrow function is clearer.

What to learn next

The basics of attaching and naming handlers are covered in the event handling overview. When the argument you need is the typed value, the onChange guide shows how to read it from the event target.

Rune AI

Rune AI

Key Insights

  • Wrap handler calls in an arrow function inside JSX.
  • A bare call runs during render, before any click.
  • Forward the event as the first argument when needed.
  • Handlers can read props and state directly through closures.
  • Use the item id from a list, not the event target.
RunePowered by Rune AI

Frequently Asked Questions

Why does onClick={handleClick(id)} break?

The parentheses call the function during rendering. React receives the return value instead of a function, so nothing runs when the user clicks.

How do I pass an argument and still read the event?

Use onClick={(e) => handleClick(e, id)}. The arrow function receives the event and forwards it along with your argument.

Can I use bind instead of an arrow function?

Yes, but it reads worse in JSX. An inline arrow function is clearer for one or two arguments and is the convention most React code follows.

Conclusion

Wrap the call in an arrow function to pass arguments at click time instead of render time. The handler reads state through its closure, and the event object stays available when you need it.