Handling Click Events: Interactive Components in React
Master React's onClick handler to make your app interactive. Learn how to trigger functions on user actions and pass event logic down to child components.
Previously in this course, we covered managing state with useState. Now that your components can hold data, it's time to make them respond to the user.
In this lesson, we’ll move beyond static rendering and learn how to capture user interactions. By the end, you’ll be able to trigger functions when a user clicks a button, a fundamental skill for building the interactive movie-browser app we've been working on.
Understanding onClick and Event Listeners
In standard HTML, you might use onclick="myFunction()" directly in your tags. React does things slightly differently. Because React uses a declarative approach, we pass a function reference to the onClick attribute (note the camelCase) on a JSX element.
When you attach an onClick listener to an element, React creates a SyntheticEvent—a cross-browser wrapper around the browser's native event. This ensures your code behaves consistently, whether your user is on Chrome, Firefox, or Safari.
A Basic Worked Example
Let’s add a "Like" button to our MovieCard component. When clicked, we want to log the movie's title to the console to confirm the interaction is working.
JSXfunction MovieCard({ title }) { const handleLike = () => { console.log(CE9178">`You liked: ${title}`); }; return ( <div className="movie-card"> <h3>{title}</h3> <button onClick={handleLike}>Like Movie</button> </div> ); }
In this snippet, we define handleLike inside the component. We then pass that function reference to the onClick prop of the button. Notice we pass handleLike (the reference), not handleLike() (the result of the function). If you add parentheses, the function will execute immediately when the component renders, which is almost certainly not what you want.
Passing Events to Child Components
As your app grows, you’ll often define interaction logic in a parent component and pass that logic down to a child. This is a common pattern for keeping your state management centralized.
Let's say we have a MovieBrowser component that keeps track of the "liked" status. We want to pass a function down to the MovieCard that handles the click.
JSXfunction MovieBrowser() { const handleLike = (movieTitle) => { alert(CE9178">`Added ${movieTitle} to favorites!`); }; return ( <div> <MovieCard title="Inception" onLike={handleLike} /> </div> ); } function MovieCard({ title, onLike }) { return ( <div className="movie-card"> <h3>{title}</h3> <button onClick={() => onLike(title)}>Like</button> </div> ); }
Here, we used an arrow function inside the onClick prop: () => onLike(title). This is a common pattern for passing arguments from a child component back up to a parent-provided function.
Hands-on Exercise
Open your movie-browser project and perform the following steps:
- Locate your
MovieCardcomponent. - Add a
buttonelement below the movie description. - Create a function
handleDetailsClickthat logs "View details for [Movie Title]" to the console. - Attach this function to the button using
onClick. - Challenge: Pass a custom message from the parent component as a prop, and have the
handleDetailsClickfunction display that message in analertwhen the button is clicked.
Common Pitfalls
Event handling is straightforward, but beginners often trip over these three issues:
- Calling the function immediately: As mentioned, avoid
onClick={handleClick()}. This executes the function during the render phase. Always useonClick={handleClick}. - Forgetting to prevent default behavior: If you are using buttons inside a
<form>element, clicking the button will trigger a page reload by default. You’ll need to accept theeventobject in your handler and callevent.preventDefault(). - Confusing synthetic events with native events: While React events are similar to native DOM events, they are not identical. If you ever need to access the underlying browser event, you can still access it via
event.nativeEvent.
Recap
We’ve covered the basics of making your UI interactive:
- Use
onClick(camelCase) to attach listeners in JSX. - Pass function references, not function calls.
- Use arrow functions to pass arguments to event handlers.
- Keep your logic clean by passing event handlers down as props when necessary.
These concepts form the foundation of how React apps handle user input. Once you master this, you'll find that React Event Handling: Understanding SyntheticEvents and Delegation becomes much easier to reason about as you scale your components.
Up next: We will learn how to update state based on its previous value to ensure our "Like" counters remain accurate.
Work with me

Next.js Full-Stack Web App Development
A fast, SEO-ready full-stack web app built with Next.js 16 — from idea to deployed product, by an engineer who ships to production.

Headless WordPress + Next.js Frontend Development
Keep WordPress for content, get a lightning-fast Next.js frontend. The best of both worlds — familiar editing, modern speed.