šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

React Events | React Tutorial

Learn about React Events in this comprehensive React tutorial for frontend web development. Dive into the SyntheticEvent system, master event delegation, and learn to handle complex interactions like form submissions and real-time input tracking.

⚔ Total XP: 0|šŸ’» react XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

Core logic.

Quick Quiz //

What is the primary danger of ignoring this concept?


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Interactivity is what turns a static page into an application, and in React that means attaching event handlers declaratively to your JSX. This lesson covers camelCase event naming, the cross-browser SyntheticEvent object, preventing default browser behavior, stopping propagation, and reading values out of form inputs.

1Declarative Interactivity

Interactivity is what separates a modern web application from a static document, and in React you handle user actions — clicks, hovers, keystrokes, form submissions — through its event system. Rather than gluing generic <script> tags onto markup, you attach the function that should run directly on the JSX element it belongs to.

Something like <button onClick={handleClick}> keeps the UI structure and the behavior that responds to it defined in exactly the same place, which is what makes React's approach declarative.

āœ•
—
+
// React Events: Handling User Input
localhost:3000
localhost:3000/concept-1
UI Rendered Successfully
React Component Preview

2camelCase Syntax

React event names must be written in camelCase — onClick, onMouseOver, onChange — rather than the all-lowercase onclick that plain HTML uses; the lowercase version triggers a console warning and is silently ignored.

You also assign the actual function reference rather than a string of code, and critically without parentheses (onClick={handleClick}, not onClick={handleClick()}), since calling it would run the function immediately during render instead of waiting for the click.

āœ•
—
+
function MyButton() {
  const handleClick = () => console.log('Clicked!');

  return <button onClick={handleClick}>Click Me</button>;
}
localhost:3000
localhost:3000/concept-2
UI Rendered Successfully
React Component Preview

3SyntheticEvent Abstraction

Whenever an event fires, React hands your handler a SyntheticEvent rather than the browser's raw native event object. This is a cross-browser wrapper that guarantees the event behaves identically whether the user is on Chrome, Firefox, Safari, or Edge.

It still exposes the same familiar interface native events provide, including e.target, e.type, e.preventDefault(), and e.stopPropagation(), so you rarely need to think about which browser is running your code.

āœ•
—
+
function logEvent(e) {
  console.log(e.type); // 'click'
  console.log(e.target); // The button element
}
localhost:3000
localhost:3000/concept-3
UI Rendered Successfully
React Component Preview

4e.preventDefault() is Crucial

Elements like <form> have default browser behavior built in — submitting one reloads the entire page, which in a React single-page app would wipe out all of your component state in an instant.

Calling e.preventDefault() inside the submit handler stops that native reload from happening, letting your own submission logic — like sending data to an API — run without losing anything the user had on screen.

āœ•
—
+
const handleSubmit = (e) => {
  e.preventDefault();
  console.log('Form submitted without reload!');
};
localhost:3000
localhost:3000/concept-4
UI Rendered Successfully
React Component Preview

5Stopping Bubbling

DOM events bubble upward: clicking a button nested inside a <div> fires the button's onClick first, then the div's onClick immediately after — which causes real bugs if the div opens a modal while the button is meant to delete an item.

Calling e.stopPropagation() inside the inner handler stops the event from continuing to bubble up, so the parent's handler never fires for that click.

āœ•
—
+
const handleChildClick = (e) => {
  e.stopPropagation();
  console.log('Child clicked only!');
};
localhost:3000
localhost:3000/concept-5
UI Rendered Successfully
React Component Preview

6Text Fields and onChange

Text inputs use onChange rather than onClick, and it fires on every single keystroke, not just once when the field loses focus. The value the user just typed lives on e.target.value.

Reading that value inside the handler is the fundamental mechanism behind Controlled Components, where a React state variable drives exactly what the input currently displays.

āœ•
—
+
<input onChange={(e) => console.log(e.target.value)} />
localhost:3000
localhost:3000/concept-6
UI Rendered Successfully
React Component Preview

7Wrapping with Inline Arrows

To pass extra data to a handler, like the ID of the item a button should delete, you can't call the function directly in JSX — onClick={deleteUser(id)} would run it immediately during render, not on click.

Instead, wrap it in an inline arrow function, onClick={() => deleteUser(id)}, so the call to deleteUser only actually happens once the click event occurs.

āœ•
—
+
<button onClick={() => deleteUser(user.id)}>Delete</button>
localhost:3000
localhost:3000/concept-7
UI Rendered Successfully
React Component Preview

8Putting it all together

Putting it together: React events are always camelCase, handlers receive a cross-browser SyntheticEvent object, e.preventDefault() stops unwanted native behavior like form reloads, and e.stopPropagation() stops an event from bubbling up to parent elements.

Once the logic inside a handler grows beyond a line or two, it's worth extracting it into a named function defined above your component's return statement, keeping the JSX itself focused purely on structure.

āœ•
—
+
<h1>Events: Secured</h1>
localhost:3000
localhost:3000/concept-8
UI Rendered Successfully
React Component Preview

9Final Check

A quick gut-check on the essentials covered so far: the value typed into an input is read from e.target.value inside an onChange handler, not from some other shorthand or a separate callback argument.

That exact path is worth memorizing, since it's the mechanism every controlled input in React depends on, whether it's a simple search box or a full multi-field form.

āœ•
—
+
e.target.value
localhost:3000
localhost:3000/concept-9
UI Rendered Successfully
React Component Preview

10Moving Forward

With event handling covered — attaching handlers declaratively, reading the SyntheticEvent, preventing default behavior, and stopping propagation — the next step is connecting these events to component memory.

React State, via useState, is what actually lets an event handler change what's on screen, turning a click or keystroke into a visible update rather than just a logged message.

āœ•
—
+
/* Ready for State */
localhost:3000
localhost:3000/concept-10
UI Rendered Successfully
React Component Preview

11Step-by-Step Breakdown

Interactivity with Events. Welcome to React Events. Interactivity is what separates a modern web application from a static document. In React, we handle user actions—like clicks, hovers, keyboard typing, and form submissions—using Events. React's event system is designed to be highly declarative, allowing you to attach JavaScript functions directly to your JSX elements.

camelCase Naming. The first major difference between React events and standard HTML events is naming. In pure HTML, event names are entirely lowercase (e.g., onclick, onmouseover). In React, all events MUST be written in camelCase (e.g., onClick, onMouseOver, onChange). If you use the lowercase version, React will throw a console warning and ignore the event completely.

Functions, Not Strings. The second major difference is how you assign the handler. In legacy HTML, you pass a string of JavaScript code (onclick="doSomething()"). In React, you pass the actual JavaScript function reference using curly braces (onClick={doSomething}). DO NOT add parentheses at the end (doSomething()), or the function will execute instantly when the component renders, instead of waiting for the click!

Which of the following is the correct way to attach a saveData function to a button click in React?

  • →<button onclick="saveData()">
  • →<button onClick={saveData()}>
  • →<button onClick={saveData}>

SyntheticEvents. When an event triggers, React passes an 'event object' (usually denoted as e or event) to your handler function. This isn't the raw browser event. It is a React 'SyntheticEvent'. It's a cross-browser wrapper that ensures the event object behaves exactly the same way whether the user is on Chrome, Firefox, Safari, or Edge. It has the same interface as native events, including e.stopPropagation() and e.preventDefault().

Preventing Default. Certain HTML elements have default behaviors built into the browser. The most common is the <form> element, which will automatically refresh the entire page when a <button type="submit"> is clicked. In a React Single Page Application (SPA), a page refresh wipes out all your state! You must call e.preventDefault() inside your handler to stop the browser from reloading.

If you have a form that triggers a full page refresh when submitted, wiping out all your React state, what method did you forget to call?

  • →e.stopPropagation()
  • →e.preventDefault()

Stopping Propagation. Events in the DOM 'bubble' upwards. If you click a <button> that is inside a <div>, the button's onClick fires first, but then the div's onClick will fire immediately after! This can cause severe bugs if the div handles navigation and the button handles deletion. To prevent an event from bubbling up to parents, use e.stopPropagation().

Form Inputs (onChange). While buttons use onClick, text inputs use onChange. The onChange event fires *every single time* a user types a keystroke. To capture what they actually typed, you access e.target.value. This is the fundamental mechanism for building Controlled Components (where React state drives the input value).

If you have an onChange event triggered by an <input>, how do you access the string the user just typed?

  • →e.text
  • →e.data
  • →e.target.value

Passing Arguments. Often, you need to pass extra data to an event handler, like the ID of the specific item you want to delete. Because you cannot execute the function directly in the JSX (e.g., onClick={deleteUser(id)} is wrong), you must wrap it in an inline arrow function: onClick={() => deleteUser(id)}.

Arguments + Event Object. What if you need to pass a custom argument AND you still need access to the SyntheticEvent object (for example, to stop propagation)? You simply pass e into the arrow function, and then hand it down to your handler alongside your custom arguments.

If you need to call updateItem(itemId) on click, AND call e.preventDefault(), which syntax is correct?

  • →onClick={updateItem(itemId, e)}
  • →onClick={(e) => { e.preventDefault(); updateItem(itemId); }}

Separation of Handlers. While inline arrow functions are convenient, putting massive blocks of logic inside your JSX makes the component unreadable. Best practice dictates that complex logic should be extracted into a named function defined above your return statement. Keep the JSX purely focused on the UI structure.

Mastery Achieved. Interactivity mastered! You understand camelCase naming, passing function references, the SyntheticEvent system, stopping propagation, and handling inputs. You are now ready to tie these events to dynamic variables using React State (useState) to build truly reactive applications.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1Interactive Elements Should Be Real Buttons and Links, Not Divs With onClick

Attaching an `onClick` handler to a `<div>` or `<span>` gives you a click listener but none of the built-in keyboard support, focus ring, or `role` semantics a `<button>` provides for free — use real interactive elements so keyboard and screen reader users can actually trigger the handler.

2Keyboard Users Need Equivalent Handlers to Mouse Users

An element that only responds to `onClick` is invisible to someone navigating by keyboard; make sure custom interactive components also handle `onKeyDown` for Enter/Space, or better yet, use a native element that supports both interactions automatically.

SEO Implications

  • 1

    Content Gated Entirely Behind a Click Handler Is Invisible to Crawlers

    If important text only renders after a user clicks something (an accordion, a 'read more' handler that fetches content), a crawler that doesn't execute that interaction may never see it — render essential content directly in the markup rather than requiring an event to reveal it.

  • 2

    preventDefault on Navigation Links Can Break Crawlability

    Calling `e.preventDefault()` on an `<a href>` to handle navigation manually is fine for client-side routing, but the `href` itself should still point to a real, crawlable URL so search engines can discover and index the linked page independent of JavaScript execution.

Best Practices

Never Call a Handler Function Directly Inside JSX

`onClick={handleClick}` passes a reference that React calls later, on click; `onClick={handleClick()}` calls it immediately during render. This mistake either breaks the UI or fires the handler on every single render instead of on user interaction.

Reach for e.stopPropagation() Only When Bubbling Actually Causes a Problem

Stopping propagation by default can silently break other handlers a parent legitimately relies on, like a modal's outside-click-to-close listener; use it deliberately, only on the specific handler where bubbling causes an actual conflict.

Frequent Bugs

THE BUG

A form handler that calls fetch or updates state seems to run, but the page reloads and all state resets anyway.

THE FIX

The submit handler is missing `e.preventDefault()`, so the browser's native form submission still triggers a full page reload alongside your handler's logic. Add `e.preventDefault()` as the first line of the handler.

THE BUG

Clicking a delete button inside a clickable card also triggers the card's own onClick handler (e.g., opening a detail view right as the item is deleted).

THE FIX

The click event bubbles from the button up to the card's div. Call `e.stopPropagation()` inside the button's own handler so the card's onClick never receives that particular click.

Real-World Examples

Deletable List Item Without Triggering Parent Navigation

A list of cards navigates to a detail page when clicked, but each card also has a delete button in the corner — the delete button's handler calls `e.stopPropagation()` so clicking it removes the item instead of also triggering the card's navigation.

<div onClick={() => navigate(`/items/${item.id}`)}>
  <p>{item.name}</p>
  <button onClick={(e) => {
    e.stopPropagation();
    deleteItem(item.id);
  }}>Delete</button>
</div>

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Mutating State Directly

// Wrong const [user, setUser] = useState({ name: 'Alice' }); user.name = 'Bob'; // React won't re-render // Correct setUser({ ...user, name: 'Bob' });

The Solution //

Never mutate a state variable directly (e.g., state.count = 1). Always use the setter function provided by useState to ensure the component re-renders.

The Error //

Missing 'key' prop in lists

// Wrong {items.map(item => <li>{item.name}</li>)} // Correct {items.map(item => <li key={item.id}>{item.name}</li>)}

The Solution //

When rendering a list of elements using .map(), always provide a unique 'key' prop to the outermost element to help React identify which items have changed.

Lesson Glossary

[01]Event Listener

A function that waits for a specific user action (like a click or keystroke) to occur.

Code Preview
onClick={...}

[02]SyntheticEvent

React's cross-browser wrapper around the native browser event object.

Code Preview
(e) => {}

[03]e.preventDefault()

A method that stops the default browser action from happening (e.g., stopping form refresh).

Code Preview
e.preventDefault()

[04]e.stopPropagation()

A method that prevents an event from bubbling up to parent elements in the DOM tree.

Code Preview
e.stopPropagation()

[05]e.target.value

The standard way to extract the current typed string out of an input field event.

Code Preview
setText(e.target.value)

[06]camelCase

The naming convention required by React for all event attributes.

Code Preview
onMouseEnter

Continue Learning