Event Handling
Event handling in React: onClick, onChange, onSubmit, event objects, preventDefault, stopPropagation, callback props, and controlled form inputs.
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:
- What events are and how React event names work
- Passing functions vs calling them in handlers
- Event objects,
targetvscurrentTarget onClick,onChange,onSubmit, and keyboard eventspreventDefault()andstopPropagation()- Passing arguments and callback props to children
- Controlled inputs, checkboxes, selects, and multi-field forms
- Common mistakes, best practices, and interview questions
1. What Is an Event?
An event is something that happens in the browser.
ClickChangeSubmitFocusBlurMouse movementKeyboard inputKey press
When a user clicks a button:
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:
<button>Click Me</button>
Make it interactive:
function App() {function handleClick() {console.log("Button clicked");}return (<button onClick={handleClick}>Click Me</button>);}
Click↓handleClick()↓"Button clicked"
3. React Event Names
React uses camelCase event names.
HTML commonly uses:
onclickonchangeonsubmit
React uses:
onClickonChangeonSubmit
<button onClick={handleClick}><input onChange={handleChange} /><form onSubmit={handleSubmit}>
HTML → Reactonclick → onClickonchange → onChangeonsubmit → onSubmitonfocus → onFocusonblur → onBluronkeydown → onKeyDownonkeyup → onKeyUp
4. Passing a Function as an Event Handler
Correct — pass the function so React calls it when the event occurs:
<button onClick={handleClick}>Click</button>
Incorrect — calls the function immediately while rendering:
<button onClick={handleClick()}>Click</button>
onClick={handleClick}↑"Call this later"onClick={handleClick()}↑"Call this now"
5. Inline Event Handlers
You can define the function directly inside JSX:
<buttononClick={() => {console.log("Clicked");}}>Click</button>
<button onClick={() => console.log("Hello")}>Say Hello</button>
Useful for small logic. For complicated logic, prefer a named handler.
6. Named Event Handlers
function App() {function handleClick() {console.log("Button clicked");}return (<button onClick={handleClick}>Click</button>);}
Common naming conventions:
handleClickhandleSubmithandleChangehandleDeletehandleLoginhandleSearchhandleToggle
Self-documenting names make the code easier to follow.
7. Event Objects
React passes an event object to the event handler.
function handleClick(event) {console.log(event);}<button onClick={handleClick}>Click</button>
function handleClick(event) {console.log(event.type);}
Output:
click
8. Getting Information from the Event
function handleClick(event) {console.log(event.currentTarget);}<button onClick={handleClick}>Buy Now</button>
Useful properties include:
event.typeevent.targetevent.currentTargetevent.keyevent.clientXevent.clientY
The exact properties available depend on the event type.
9. target vs currentTarget
<button onClick={handleClick}><span>Buy</span></button>
If the user clicks the <span>:
event.target↓<span>event.currentTarget↓<button>
target
The element where the event originated.
currentTarget
The element whose event handler is currently executing.
function handleClick(event) {console.log(event.target);console.log(event.currentTarget);}
10. Handling Input Changes
One of the most common React events is onChange.
function App() {function handleChange(event) {console.log(event.target.value);}return (<inputtype="text"onChange={handleChange}/>);}
As the user types:
RReReaReacReact
the handler receives the updated input value.
11. Event Handling with State
Event handling becomes much more powerful when combined with state.
import { useState } from "react";function App() {const [name, setName] = useState("");function handleChange(event) {setName(event.target.value);}return (<div><inputvalue={name}onChange={handleChange}/><p>Hello, {name}</p></div>);}
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.
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.
event.preventDefault();
Then we can:
Validate data↓Call API↓Show loading state↓Handle success/error
14. Button Click Handling
function App() {function handleLogin() {console.log("Logging in...");}return (<button onClick={handleLogin}>Login</button>);}
Multiple buttons can have different handlers:
<button onClick={handleLogin}>Login</button><button onClick={handleLogout}>Logout</button>
15. Passing Arguments to Event Handlers
const products = [{ id: 1, name: "Laptop" },{ id: 2, name: "Phone" }];{products.map((product) => (<buttonkey={product.id}onClick={() => handleBuy(product.id)}>Buy {product.name}</button>))}function handleBuy(productId) {console.log("Buying product:", productId);}
Important distinction:
onClick={handleBuy}onClick={() => handleBuy(product.id)}
The second form lets you pass additional data.
16. Passing Both Arguments and the Event
<buttononClick={(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
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
onClickonDoubleClickonMouseEnteronMouseLeaveonMouseMoveonMouseDownonMouseUp
<divonMouseEnter={handleMouseEnter}onMouseLeave={handleMouseLeave}>Hover over me</div>
Keyboard Events
onKeyDownonKeyUp
function SearchBox() {function handleKeyDown(event) {if (event.key === "Enter") {console.log("Search");}}return (<input onKeyDown={handleKeyDown} />);}
Form Events
onChangeonSubmitonFocusonBlur
<inputonFocus={handleFocus}onBlur={handleBlur}/>
19. Keyboard Event Handling
Keyboard events are useful for search boxes, forms, shortcuts, and accessibility.
function Search() {function handleKeyDown(event) {if (event.key === "Enter") {performSearch();}}return (<inputplaceholder="Search..."onKeyDown={handleKeyDown}/>);}
The event object provides event.key:
EnterEscapeArrowUpArrowDownab1
20. Preventing Default Behavior
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.
<div onClick={handleParentClick}><button onClick={handleButtonClick}>Click</button></div>
Button clicked↓Button handler↓Parent handler
Stop propagation when needed:
function handleButtonClick(event) {event.stopPropagation();console.log("Button clicked");}
22. Event Propagation
The browser event system has two major propagation phases:
Capture phase↓Target phase↓Bubble phase
React event handling commonly works with bubbling.
<div onClick={() => console.log("Parent")}><button onClick={() => console.log("Child")}>Click</button></div>
Clicking the button typically results in:
ChildParent
because the event bubbles upward.
23. Capturing Events
React supports capture-phase handlers using the Capture suffix.
<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.
function App() {function handleSave() {console.log("Saved");}return (<SaveButton onSave={handleSave} />);}function SaveButton({ onSave }) {return (<button onClick={onSave}>Save</button>);}
Parent││ passes function▼Child││ user clicks▼onSave()│▼Parent handler executes
25. Naming Callback Props
A common convention:
onClickonSaveonDeleteonSubmitonChangeonSelect
function UserCard({ user, onDelete }) {return (<button onClick={() => onDelete(user.id)}>Delete</button>);}<UserCarduser={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.
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.
function Form() {const [email, setEmail] = useState("");function handleChange(event) {setEmail(event.target.value);}return (<inputvalue={email}onChange={handleChange}/>);}
React State↓value↓InputUser types↓onChange↓setEmail()↓State
React becomes the source of truth.
28. Handling Multiple Inputs
function Form() {const [form, setForm] = useState({name: "",email: ""});function handleChange(event) {const { name, value } = event.target;setForm({...form,[name]: value});}return (<form><inputname="name"value={form.name}onChange={handleChange}/><inputname="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.
function Preferences() {const [notifications, setNotifications] = useState(false);function handleChange(event) {setNotifications(event.target.checked);}return (<label><inputtype="checkbox"checked={notifications}onChange={handleChange}/>Enable notifications</label>);}
Text input → valueCheckbox → checked
30. Handling Select Elements
function CountrySelector() {const [country, setCountry] = useState("");function handleChange(event) {setCountry(event.target.value);}return (<selectvalue={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
// Bad<button onClick={handleClick()}>// Correct<button onClick={handleClick}>
Mistake 2: Forgetting event.preventDefault()
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.
function handleSubmit() {validate();save();notify();redirect();}<button onClick={handleSubmit}>Submit</button>
Mistake 4: Mutating state inside event handlers
// Baduser.name = "Rahul";// GoodsetUser({...user,name: "Rahul"});
Mistake 5: Forgetting to pass arguments correctly
// Bad — executes immediately<button onClick={handleDelete(user.id)}>// Correct<button onClick={() => handleDelete(user.id)}>
32. Event Handling Best Practices
- Use descriptive handler names (
handleSubmit,handleDelete) - Keep handlers focused on one meaningful interaction
- Move complex logic into named functions
- Pass callbacks through props for reusable children
- Use
preventDefault()intentionally — not everywhere automatically - Use
stopPropagation()only when needed - Keep state updates immutable via setters
33. Practical Example — Counter
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>);}
Click +↓handleIncrement()↓setCount()↓State changes↓React renders↓New count displayed
34. Practical Example — Search Box
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}><inputvalue={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
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) => (<TodoItemkey={todo.id}todo={todo}onDelete={handleDelete}/>))}</ul>);}
Parent owns state↓passes callback↓Child detects event↓callback(id)↓Parent updates state↓React renders new UI
36. Event Handling Mental Model
USER ACTION↓BROWSER EVENT↓REACT EVENT HANDLER↓APPLICATION LOGIC↓STATE UPDATE↓RENDER↓UPDATED UI
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?
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?
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?
<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.
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
Parent↓UserCard
Pass onDelete from parent to UserCard; the child's Delete button triggers the parent handler.
39. Quick Cheat Sheet
| Task | React Pattern |
|---|---|
| Click | onClick={handleClick} |
| Input change | onChange={handleChange} |
| Form submit | onSubmit={handleSubmit} |
| Keyboard | onKeyDown={handleKeyDown} |
| Focus / Blur | onFocus / onBlur |
| Get input value | event.target.value |
| Checkbox | event.target.checked |
| Prevent default | event.preventDefault() |
| Stop propagation | event.stopPropagation() |
| Pass argument | onClick={() => handleDelete(id)} |
| Pass callback | <Child onSave={handleSave} /> |
Key Takeaway
Event handling is what allows React applications to respond to users.
The fundamental pattern is:
function handleClick() {// application logic}return (<button onClick={handleClick}>Click</button>);
For dynamic actions, forms, inputs, and reusable children:
<button onClick={() => handleDelete(item.id)}>Delete</button><form onSubmit={handleSubmit}><inputvalue={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.