React · State & Events

Event Handling

React events look like HTML attributes, but you pass functions instead of strings. Clicks, typing, form submits — all handled with the same simple pattern.

Beginner 5 min Lesson 9 of 42Examples target React 19 with Vite.
Before you start:Components
0/42 in React
On this page · 5 min · Beginner

Learning objectives#

  • Attach handlers with onClick, onChange and onSubmit
  • Pass arguments to handlers correctly
  • Use the event object and preventDefault
  • Name and pass handlers between components

Explanation#

Events use camelCase props with a function: <button onClick={handleClick}>. Pass the function itself — do not call it.

To pass arguments, wrap in an arrow: onClick={() => remove(item.id)}.

The handler receives a synthetic event with the familiar API: e.target.value, e.preventDefault(), e.stopPropagation(), e.key for keyboard events.

Forms: handle onSubmit on the <form> and call e.preventDefault() so the page does not reload.

Conventions: handler functions are named handleSomething; props that accept handlers are named onSomething (onSave={handleSave}).

Syntax#

JSX Illustrative
<button onClick={handleSave}>Save</button>
<button onClick={() => remove(id)}>Delete</button>
<input onChange={e => setName(e.target.value)} />
<form onSubmit={e => { e.preventDefault(); send(); }}>

Code example: Clicks, keys and a form#

JSXEvents.jsx Runnable
import { useState } from 'react';


export default function Events() {
  const [log, setLog] = useState([]);
  const [name, setName] = useState('');
  const add = message => setLog(prev => [message, ...prev].slice(0, 5));


  function handleSubmit(e) {
    e.preventDefault();                       // no page reload
    add(`Submitted: ${name || '(empty)'}`);
    setName('');
  }


  function handleKeyDown(e) {
    if (e.key === 'Escape') {
      setName('');
      add('Cleared with Escape');
    }
  }


  return (
    <>
      {['Pen', 'Notebook'].map(item => (
        <button key={item} onClick={() => add(`Clicked ${item}`)}>{item}</button>
      ))}


      <form onSubmit={handleSubmit}>
        <input
          value={name}
          onChange={e => setName(e.target.value)}
          onKeyDown={handleKeyDown}
          aria-label="Your name"
        />
        <button type="submit">Send</button>
      </form>


      <ol>{log.map((line, i) => <li key={i}>{line}</li>)}</ol>
    </>
  );
}
Expected output
Clicking “Pen” adds “Clicked Pen” to the log. Typing a name and pressing Enter or Send adds “Submitted: Asha” without reloading the page. Pressing Escape in the input clears it and logs “Cleared with Escape”. The log keeps the latest five lines.

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. Each item button uses an arrow function to pass its own name to add.
  2. onChange keeps the input in sync with the name state.
  3. onKeyDown checks e.key to react to Escape.
  4. handleSubmit runs for both Enter and the Send button and prevents the page reload.

Real-world use case#

A chat input sends on Enter, adds a newline on Shift+Enter, and clears on Escape — all from one onKeyDown handler reading e.key and e.shiftKey.

Common mistakes#

onClick={handleClick()}

This calls the function during render (and may loop forever if it sets state). Pass handleClick or () => handleClick(x).

Forgetting preventDefault on forms

Without it the browser submits the form and reloads the page, losing your state.

onClick on a div for actions

Divs are not focusable or keyboard-accessible. Use <button>.

Best practices#

  • Name handlers handleX and props onX
  • Use buttons for actions
  • Handle forms with onSubmit
  • Keep handlers short; move logic into functions

Remember this#

Pass the function, do not call it.

Arguments? Wrap: () => fn(arg).

Forms: onSubmit + e.preventDefault().

Practice exercise#

Your task: Build a LikeButton that shows "♡ Like" and becomes "♥ Liked" when clicked, toggling back on the next click.

Need a hint?
Boolean state toggled with setLiked(l => !l).
Show solution
JSX Runnable
import { useState } from 'react';


export default function LikeButton() {
  const [liked, setLiked] = useState(false);
  return (
    <button onClick={() => setLiked(l => !l)} aria-pressed={liked}>
      {liked ? '♥ Liked' : '♡ Like'}
    </button>
  );
}

Mini quiz#

Event Handling quizFind the error Question 1 of 3

What is wrong here?

<button onClick={deleteItem(5)}>Delete</button>
Score so far: 0/0

Want more? Practise all React MCQs · React interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.