React Tutorial 0/120 lessons ~6 min read Lesson 24

    Event Handling

    Event handling in React: onClick, onChange, onSubmit, event objects, preventDefault, stopPropagation, callback props, and controlled form inputs.

    Course progress0%
    Focus
    42 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Event Handling

    Event Handling is one of the foundational pieces of modern React engineering.

    A React application is not just about displaying data. Users need to interact with the interface:

    • Clicking buttons
    • Typing into inputs
    • Submitting forms
    • Selecting options
    • Hovering over elements
    • Pressing keyboard keys
    • Checking checkboxes
    • Dragging elements
    • Opening and closing menus

    React provides a clean way to respond to these interactions using event handlers. Once you understand event handling, React components become interactive rather than static.

    Learning Objectives

    By the end of this lesson, you will understand:

    1. What events are and how React event names work
    2. Passing functions vs calling them in handlers
    3. Event objects, target vs currentTarget
    4. onClick, onChange, onSubmit, and keyboard events
    5. preventDefault() and stopPropagation()
    6. Passing arguments and callback props to children
    7. Controlled inputs, checkboxes, selects, and multi-field forms
    8. Common mistakes, best practices, and interview questions

    1. What Is an Event?

    An event is something that happens in the browser.

    text
    Click
    Change
    Submit
    Focus
    Blur
    Mouse movement
    Keyboard input
    Key press

    When a user clicks a button:

    text
    User clicks button
    ↓
    Browser generates event
    ↓
    React receives event
    ↓
    Event handler executes
    ↓
    Application responds

    In React, we connect an event to a function.

    2. Basic Event Handling

    A button that does nothing:

    tsx
    <button>Click Me</button>

    Make it interactive:

    tsx
    function App() {
    function handleClick() {
    console.log("Button clicked");
    }
    return (
    <button onClick={handleClick}>
    Click Me
    </button>
    );
    }
    text
    Click
    ↓
    handleClick()
    ↓
    "Button clicked"

    3. React Event Names

    React uses camelCase event names.

    HTML commonly uses:

    html
    onclick
    onchange
    onsubmit

    React uses:

    tsx
    onClick
    onChange
    onSubmit
    tsx
    <button onClick={handleClick}>
    <input onChange={handleChange} />
    <form onSubmit={handleSubmit}>
    text
    HTML → React
    onclick → onClick
    onchange → onChange
    onsubmit → onSubmit
    onfocus → onFocus
    onblur → onBlur
    onkeydown → onKeyDown
    onkeyup → onKeyUp

    4. Passing a Function as an Event Handler

    Correct — pass the function so React calls it when the event occurs:

    tsx
    <button onClick={handleClick}>
    Click
    </button>

    Incorrect — calls the function immediately while rendering:

    tsx
    <button onClick={handleClick()}>
    Click
    </button>
    text
    onClick={handleClick}
    ↑
    "Call this later"
    onClick={handleClick()}
    ↑
    "Call this now"

    5. Inline Event Handlers

    You can define the function directly inside JSX:

    tsx
    <button
    onClick={() => {
    console.log("Clicked");
    }}
    >
    Click
    </button>
    tsx
    <button onClick={() => console.log("Hello")}>
    Say Hello
    </button>

    Useful for small logic. For complicated logic, prefer a named handler.

    6. Named Event Handlers

    tsx
    function App() {
    function handleClick() {
    console.log("Button clicked");
    }
    return (
    <button onClick={handleClick}>
    Click
    </button>
    );
    }

    Common naming conventions:

    text
    handleClick
    handleSubmit
    handleChange
    handleDelete
    handleLogin
    handleSearch
    handleToggle

    Self-documenting names make the code easier to follow.

    7. Event Objects

    React passes an event object to the event handler.

    tsx
    function handleClick(event) {
    console.log(event);
    }
    <button onClick={handleClick}>
    Click
    </button>
    tsx
    function handleClick(event) {
    console.log(event.type);
    }

    Output:

    text
    click

    8. Getting Information from the Event

    tsx
    function handleClick(event) {
    console.log(event.currentTarget);
    }
    <button onClick={handleClick}>
    Buy Now
    </button>

    Useful properties include:

    text
    event.type
    event.target
    event.currentTarget
    event.key
    event.clientX
    event.clientY

    The exact properties available depend on the event type.

    9. target vs currentTarget

    tsx
    <button onClick={handleClick}>
    <span>Buy</span>
    </button>

    If the user clicks the <span>:

    text
    event.target
    ↓
    <span>
    event.currentTarget
    ↓
    <button>

    target

    The element where the event originated.

    currentTarget

    The element whose event handler is currently executing.

    tsx
    function handleClick(event) {
    console.log(event.target);
    console.log(event.currentTarget);
    }

    10. Handling Input Changes

    One of the most common React events is onChange.

    tsx
    function App() {
    function handleChange(event) {
    console.log(event.target.value);
    }
    return (
    <input
    type="text"
    onChange={handleChange}
    />
    );
    }

    As the user types:

    text
    R
    Re
    Rea
    Reac
    React

    the handler receives the updated input value.

    11. Event Handling with State

    Event handling becomes much more powerful when combined with state.

    tsx
    import { useState } from "react";
    function App() {
    const [name, setName] = useState("");
    function handleChange(event) {
    setName(event.target.value);
    }
    return (
    <div>
    <input
    value={name}
    onChange={handleChange}
    />
    <p>Hello, {name}</p>
    </div>
    );
    }
    text
    User types
    ↓
    onChange
    ↓
    handleChange()
    ↓
    setName()
    ↓
    State updates
    ↓
    Component renders again
    ↓
    UI displays new value

    This pattern is fundamental to React forms.

    12. Handling Form Submission

    React forms use onSubmit.

    tsx
    function LoginForm() {
    function handleSubmit(event) {
    event.preventDefault();
    console.log("Form submitted");
    }
    return (
    <form onSubmit={handleSubmit}>
    <input type="email" />
    <input type="password" />
    <button type="submit">
    Login
    </button>
    </form>
    );
    }

    The important line is event.preventDefault().

    13. Why preventDefault()?

    Browsers have default behavior for many events. For form submission, the browser may perform a full page reload. In React apps, we usually want React to handle the process instead.

    tsx
    event.preventDefault();

    Then we can:

    text
    Validate data
    ↓
    Call API
    ↓
    Show loading state
    ↓
    Handle success/error

    14. Button Click Handling

    tsx
    function App() {
    function handleLogin() {
    console.log("Logging in...");
    }
    return (
    <button onClick={handleLogin}>
    Login
    </button>
    );
    }

    Multiple buttons can have different handlers:

    tsx
    <button onClick={handleLogin}>
    Login
    </button>
    <button onClick={handleLogout}>
    Logout
    </button>

    15. Passing Arguments to Event Handlers

    tsx
    const products = [
    { id: 1, name: "Laptop" },
    { id: 2, name: "Phone" }
    ];
    {products.map((product) => (
    <button
    key={product.id}
    onClick={() => handleBuy(product.id)}
    >
    Buy {product.name}
    </button>
    ))}
    function handleBuy(productId) {
    console.log("Buying product:", productId);
    }

    Important distinction:

    tsx
    onClick={handleBuy}
    onClick={() => handleBuy(product.id)}

    The second form lets you pass additional data.

    16. Passing Both Arguments and the Event

    tsx
    <button
    onClick={(event) => handleDelete(event, user.id)}
    >
    Delete
    </button>
    function handleDelete(event, userId) {
    event.preventDefault();
    console.log(userId);
    }

    Order is up to your function design — stay consistent.

    17. Event Handling in List Components

    tsx
    function TodoList({ todos, onDelete }) {
    return (
    <ul>
    {todos.map((todo) => (
    <li key={todo.id}>
    {todo.title}
    <button onClick={() => onDelete(todo.id)}>
    Delete
    </button>
    </li>
    ))}
    </ul>
    );
    }

    The list identifies the item with key; the event identifies the action with onClick. These two concepts work together constantly in React.

    18. Common React Events

    Mouse Events

    tsx
    onClick
    onDoubleClick
    onMouseEnter
    onMouseLeave
    onMouseMove
    onMouseDown
    onMouseUp
    tsx
    <div
    onMouseEnter={handleMouseEnter}
    onMouseLeave={handleMouseLeave}
    >
    Hover over me
    </div>

    Keyboard Events

    tsx
    onKeyDown
    onKeyUp
    tsx
    function SearchBox() {
    function handleKeyDown(event) {
    if (event.key === "Enter") {
    console.log("Search");
    }
    }
    return (
    <input onKeyDown={handleKeyDown} />
    );
    }

    Form Events

    tsx
    onChange
    onSubmit
    onFocus
    onBlur
    tsx
    <input
    onFocus={handleFocus}
    onBlur={handleBlur}
    />

    19. Keyboard Event Handling

    Keyboard events are useful for search boxes, forms, shortcuts, and accessibility.

    tsx
    function Search() {
    function handleKeyDown(event) {
    if (event.key === "Enter") {
    performSearch();
    }
    }
    return (
    <input
    placeholder="Search..."
    onKeyDown={handleKeyDown}
    />
    );
    }

    The event object provides event.key:

    text
    Enter
    Escape
    ArrowUp
    ArrowDown
    a
    b
    1

    20. Preventing Default Behavior

    tsx
    function handleSubmit(event) {
    event.preventDefault();
    // Custom submission logic
    }
    function handleLinkClick(event) {
    event.preventDefault();
    console.log("Custom navigation");
    }

    Use preventDefault() when you intentionally want to override the browser's default action.

    21. Stopping Event Propagation

    Events can propagate through the DOM.

    tsx
    <div onClick={handleParentClick}>
    <button onClick={handleButtonClick}>
    Click
    </button>
    </div>
    text
    Button clicked
    ↓
    Button handler
    ↓
    Parent handler

    Stop propagation when needed:

    tsx
    function handleButtonClick(event) {
    event.stopPropagation();
    console.log("Button clicked");
    }

    22. Event Propagation

    The browser event system has two major propagation phases:

    text
    Capture phase
    ↓
    Target phase
    ↓
    Bubble phase

    React event handling commonly works with bubbling.

    tsx
    <div onClick={() => console.log("Parent")}>
    <button onClick={() => console.log("Child")}>
    Click
    </button>
    </div>

    Clicking the button typically results in:

    text
    Child
    Parent

    because the event bubbles upward.

    23. Capturing Events

    React supports capture-phase handlers using the Capture suffix.

    tsx
    <div onClickCapture={handleCapture}>
    <button onClick={handleClick}>
    Click
    </button>
    </div>

    The capture handler executes during the capture phase before the event reaches the target. You rarely need capture for everyday components, but it helps with advanced event behavior.

    24. Event Handlers and Props

    Event handlers can be passed to child components as props.

    tsx
    function App() {
    function handleSave() {
    console.log("Saved");
    }
    return (
    <SaveButton onSave={handleSave} />
    );
    }
    function SaveButton({ onSave }) {
    return (
    <button onClick={onSave}>
    Save
    </button>
    );
    }
    text
    Parent
    │
    │ passes function
    ▼
    Child
    │
    │ user clicks
    ▼
    onSave()
    │
    ▼
    Parent handler executes

    25. Naming Callback Props

    A common convention:

    text
    onClick
    onSave
    onDelete
    onSubmit
    onChange
    onSelect
    tsx
    function UserCard({ user, onDelete }) {
    return (
    <button onClick={() => onDelete(user.id)}>
    Delete
    </button>
    );
    }
    <UserCard
    user={user}
    onDelete={handleDelete}
    />

    26. Event Handling and Component Responsibility

    The component that knows what should happen can own the logic, while the component that detects the interaction can trigger the callback.

    text
    UserCard
    │
    │ detects click
    ▼
    onDelete(id)
    │
    ▼
    Parent
    │
    │ owns deletion logic
    ▼
    State update / API call

    This keeps reusable UI components flexible.

    27. Controlled Inputs and Events

    A controlled input gets its value from React state.

    tsx
    function Form() {
    const [email, setEmail] = useState("");
    function handleChange(event) {
    setEmail(event.target.value);
    }
    return (
    <input
    value={email}
    onChange={handleChange}
    />
    );
    }
    text
    React State
    ↓
    value
    ↓
    Input
    User types
    ↓
    onChange
    ↓
    setEmail()
    ↓
    State

    React becomes the source of truth.

    28. Handling Multiple Inputs

    tsx
    function Form() {
    const [form, setForm] = useState({
    name: "",
    email: ""
    });
    function handleChange(event) {
    const { name, value } = event.target;
    setForm({
    ...form,
    [name]: value
    });
    }
    return (
    <form>
    <input
    name="name"
    value={form.name}
    onChange={handleChange}
    />
    <input
    name="email"
    value={form.email}
    onChange={handleChange}
    />
    </form>
    );
    }

    The same handler can manage multiple fields via event.target.name and event.target.value.

    29. Handling Checkboxes

    Checkboxes use event.target.checked instead of value.

    tsx
    function Preferences() {
    const [notifications, setNotifications] = useState(false);
    function handleChange(event) {
    setNotifications(event.target.checked);
    }
    return (
    <label>
    <input
    type="checkbox"
    checked={notifications}
    onChange={handleChange}
    />
    Enable notifications
    </label>
    );
    }
    text
    Text input → value
    Checkbox → checked

    30. Handling Select Elements

    tsx
    function CountrySelector() {
    const [country, setCountry] = useState("");
    function handleChange(event) {
    setCountry(event.target.value);
    }
    return (
    <select
    value={country}
    onChange={handleChange}
    >
    <option value="">Select country</option>
    <option value="india">India</option>
    <option value="usa">USA</option>
    <option value="uk">UK</option>
    </select>
    );
    }

    31. Common Mistakes

    Mistake 1: Calling the handler immediately

    tsx
    // Bad
    <button onClick={handleClick()}>
    // Correct
    <button onClick={handleClick}>

    Mistake 2: Forgetting event.preventDefault()

    tsx
    function handleSubmit(event) {
    event.preventDefault();
    // custom logic
    }

    Mistake 3: Overusing inline logic

    Move complicated logic into a named function instead of a huge inline arrow in JSX.

    tsx
    function handleSubmit() {
    validate();
    save();
    notify();
    redirect();
    }
    <button onClick={handleSubmit}>
    Submit
    </button>

    Mistake 4: Mutating state inside event handlers

    tsx
    // Bad
    user.name = "Rahul";
    // Good
    setUser({
    ...user,
    name: "Rahul"
    });

    Mistake 5: Forgetting to pass arguments correctly

    tsx
    // Bad — executes immediately
    <button onClick={handleDelete(user.id)}>
    // Correct
    <button onClick={() => handleDelete(user.id)}>

    32. Event Handling Best Practices

    1. Use descriptive handler names (handleSubmit, handleDelete)
    2. Keep handlers focused on one meaningful interaction
    3. Move complex logic into named functions
    4. Pass callbacks through props for reusable children
    5. Use preventDefault() intentionally — not everywhere automatically
    6. Use stopPropagation() only when needed
    7. Keep state updates immutable via setters

    33. Practical Example — Counter

    tsx
    import { useState } from "react";
    function Counter() {
    const [count, setCount] = useState(0);
    function handleIncrement() {
    setCount((currentCount) => currentCount + 1);
    }
    function handleDecrement() {
    setCount((currentCount) => currentCount - 1);
    }
    return (
    <div>
    <h2>{count}</h2>
    <button onClick={handleIncrement}>+</button>
    <button onClick={handleDecrement}>-</button>
    </div>
    );
    }
    text
    Click +
    ↓
    handleIncrement()
    ↓
    setCount()
    ↓
    State changes
    ↓
    React renders
    ↓
    New count displayed

    34. Practical Example — Search Box

    tsx
    import { useState } from "react";
    function SearchBox() {
    const [query, setQuery] = useState("");
    function handleChange(event) {
    setQuery(event.target.value);
    }
    function handleSearch(event) {
    event.preventDefault();
    console.log("Searching for:", query);
    }
    return (
    <form onSubmit={handleSearch}>
    <input
    value={query}
    onChange={handleChange}
    placeholder="Search..."
    />
    <button type="submit">
    Search
    </button>
    </form>
    );
    }

    Combines state, onChange, onSubmit, the event object, preventDefault(), and a controlled input — patterns you will use constantly.

    35. Practical Example — Delete Item

    tsx
    function TodoItem({ todo, onDelete }) {
    return (
    <li>
    {todo.title}
    <button onClick={() => onDelete(todo.id)}>
    Delete
    </button>
    </li>
    );
    }
    function TodoList() {
    const [todos, setTodos] = useState(initialTodos);
    function handleDelete(id) {
    setTodos((currentTodos) =>
    currentTodos.filter((todo) => todo.id !== id)
    );
    }
    return (
    <ul>
    {todos.map((todo) => (
    <TodoItem
    key={todo.id}
    todo={todo}
    onDelete={handleDelete}
    />
    ))}
    </ul>
    );
    }
    text
    Parent owns state
    ↓
    passes callback
    ↓
    Child detects event
    ↓
    callback(id)
    ↓
    Parent updates state
    ↓
    React renders new UI

    36. Event Handling Mental Model

    text
    USER ACTION
    ↓
    BROWSER EVENT
    ↓
    REACT EVENT HANDLER
    ↓
    APPLICATION LOGIC
    ↓
    STATE UPDATE
    ↓
    RENDER
    ↓
    UPDATED UI
    text
    User clicks Delete
    ↓
    onClick
    ↓
    handleDelete(id)
    ↓
    setTodos(...)
    ↓
    State changes
    ↓
    React renders
    ↓
    Todo disappears

    37. Interview Questions

    1. How do you handle events in React?

    Use event props such as onClick, onChange, and onSubmit, and provide functions as handlers.

    2. onClick={handleClick} vs onClick={handleClick()}?

    onClick={handleClick} passes the function. onClick={handleClick()} calls it immediately during rendering.

    3. How do you pass arguments to an event handler?

    tsx
    onClick={() => handleDelete(id)}

    4. What is preventDefault()?

    It prevents the browser's default behavior for an event — commonly used with form submission.

    5. What is event propagation?

    The process through which an event travels through the DOM, including capture and bubbling phases.

    6. What does stopPropagation() do?

    It prevents the event from continuing through the propagation path.

    7. target vs currentTarget?

    target is where the event originated. currentTarget is the element whose handler is currently executing.

    8. How do you handle input changes?

    tsx
    function handleChange(event) {
    setValue(event.target.value);
    }

    9. How do you handle checkbox changes?

    Use event.target.checked rather than event.target.value.

    10. How do child components communicate an event to parents?

    tsx
    <Child onDelete={handleDelete} />
    // child: onDelete(id);

    38. Practice Exercises

    Exercise 1 — Button Click

    Create a button that logs Button clicked! when clicked.

    Exercise 2 — Counter

    Build a counter with +, -, and Reset buttons.

    Exercise 3 — Input

    Create an input and display its current value below it.

    text
    Input:
    [ React ]
    You typed: React

    Exercise 4 — Form

    Form with name, email, and submit. Prevent default submission and print form data to the console.

    Exercise 5 — Search

    Build a search box that acts when the user presses Enter.

    Exercise 6 — Todo Delete

    Todo list with Delete per item; clicking Delete removes only that todo.

    Exercise 7 — Parent/Child Callback

    text
    Parent
    ↓
    UserCard

    Pass onDelete from parent to UserCard; the child's Delete button triggers the parent handler.

    39. Quick Cheat Sheet

    TaskReact Pattern
    ClickonClick={handleClick}
    Input changeonChange={handleChange}
    Form submitonSubmit={handleSubmit}
    KeyboardonKeyDown={handleKeyDown}
    Focus / BluronFocus / onBlur
    Get input valueevent.target.value
    Checkboxevent.target.checked
    Prevent defaultevent.preventDefault()
    Stop propagationevent.stopPropagation()
    Pass argumentonClick={() => handleDelete(id)}
    Pass callback<Child onSave={handleSave} />

    Key Takeaway

    Event handling is what allows React applications to respond to users.

    The fundamental pattern is:

    tsx
    function handleClick() {
    // application logic
    }
    return (
    <button onClick={handleClick}>
    Click
    </button>
    );

    For dynamic actions, forms, inputs, and reusable children:

    tsx
    <button onClick={() => handleDelete(item.id)}>
    Delete
    </button>
    <form onSubmit={handleSubmit}>
    <input
    value={value}
    onChange={handleChange}
    />
    <Child onAction={handleAction} />

    User interaction triggers an event handler, the handler performs application logic or updates state, and React re-renders the UI to reflect the new state.

    Once you understand this flow, you have the foundation for building interactive React applications.

    Ready to mark this lesson complete?Track your journey across the entire course.