React Event Handlers Tutorial: Complete Guide to onClick and Event Handling
Learn how to handle user interactions in React by implementing event handlers for clicks, form submissions, and more.
Introduction
A button
is meant to be clicked, and when it’s clicked we intrinsically expect something to happen? right?
Well, the thing that will happen is defined by you the developer as a Javascript
function doing something, let’s say displaying an alert message as an example.
The function whose job is to respond to an event triggered by something like a user interaction such as clicking is called an event handler
, and it’s a normal javascript function declared within the component. And can be attached to any JSX
element such as buttons
, divs
, inputs
and so on.
Usually, the React
community follows the naming convention that consists of starting the event handler’s name with handle
followed by the event name. Some examples of that include: handleClick
, handleHover
, handleFocus
and so on.
React
makes attaching an event handler to a JSX element really straightforward.
We just have to assign the event handler (aka our locally declared function) into a special type of props
starting with on
then followed by the name of the event such as onClick
, onFocus
, onHover
and so on.
In this article, we will dive deeper into event handlers while exploring important concepts that every developer needs to master such as:
-
Passing event handlers between
React
components. -
Event propagation and why understanding it is so important.
-
And finally, How to stop event propagation and other browser defaults behaviors when needed.
So if that sounds interesting let’s dive in.
Event Handlers Basics
Let’s say that we’ve got a component, rendering a button
saying Click me
. Let’s define an event handler named handleClick
as a locally declared function within the component as we’ve discussed previously.
And then attach it to the onClick
button prop.
Keep in mind that you need to just assign the function name without calling it like this.
function Button(){
function handleClick(){
alert("Stop Clicking")
}
return (
<button onClick={handleClick}>Click me</button> {/* ✅ */}
{/* <button onClick={handleClick()} />Click me </button> ❌ */ }
)
}
Calling it will just make the function run at every render which is not obviously our goal here.
Whenever the button
gets clicked by the user **the function which is attached to the onClick
prop is going to get called. Consequently the alert message will get displayed.
What if our component is receiving a username
prop, can we accesses it in the event handler and concatenate it with a “Hi” message as shown bellow?
function Button({username}){
function handleClick(){
alert("Hi "+ username)
}
return (
<button onClick={handleClick}>Click me</button> {/* ✅ */}
)
}
Yes, actually that’s one of the advantages of declaring an event handler within the component. Doing so allows the event handler to access its parent’s outer scope variables or functions such as props
or any other stuff.
Passing Event Handlers as Props
Okay, now imagine that you want to use the Button
component in multiple places.
Declaring the handleClick
event inside the component itself, will just make it less reusable. So can we instead pass the event handler as a prop.
Yes, absolutely! As you may know functions are first class citizens in Javascript
. Consequently, they can be passed to other function, therefore React
components. So it’s obviously possible to do that.
Let’s make our Button
component accept a new prop called onClick
, assign it to the button
’s onClick prop, then declare a handleClick
event handler inside the parent component itself. And then pass it to the Button
child component.
function Button({username,onClick}){
return (
<button onClick={onClick}>Click me</button>
)
}
function App(){
const username = "Sid Ali"
function handleClick(){
alert("Hi "+ username)
}
return (
<div>
<Button onClick={handleClick} username={username} />
</div>
)
}
By convention event handler props are named exactly as the
JSX
elements built-in events props. So they start withon
followed by either the event name or the interaction that need to be performed such asonClick
,onUploadFile
,onTryingToFindARandomName
and so on.
Event Propagation and Bubbling
Now let’s move on into a very important and interesting concept that is known as event bubbling or propagation.
But before that let me ask you a simple question.
What will happen if you have clicked on the child component of two nested JSX
elements both having the onClick
event attached to them? Which component will show its corresponding alert message?
Let’s say that we have a Parent
and Child
components.
An onClick
event listener displaying an alert, is attached to the Child
component and the parent component.
function Parent(){
return (
<div onClick={()=>alert("Hello From Parent")}>
<Child1 />
</div>
)
}
function Child(){
return (
<button onClick={()=>alert("Hello from Child")}>Click me</button>
)
}
-> (1) Hello from Child
-> (2) Hello from Parent
The answer as you may have guessed is both but in a special order.
The alert message corresponding to the Child
component will get displayed first, then the Parent
will follow after that.
We call what have just happened event propagation or bubbling we say that the click event has propagated from the child to the parent.
Stopping Event Propagation
If you happen to be bothered by such default behavior you can stop the propagation by doing as follows:
function Child(){
return (
<button onClick={(e)=>{
e.stopPropagation()
alert("Hello from Child")}
}>Click me</button>
)
}
Every event handler has access to an optional
e
argument which is shorthand standing forevent
that you can use to either read information about it or perform actions on the event that has just have occurred.
Among those actions is being able to call the stopPropagation
method on the e
object to prevent the event from bubbling to its parent.
Alternative to Propagation
When stopping the default browser’s propagation, you may want to call the parent’s event handler after running some code at the child level.
You can absolutely do that as an alternative to propagation in the React
way. By just passing the parent’s event handler as a prop and then calling it after stopping the propagation and running some code.
function Parent(){
function handleClick(){
alert("Hello From Parent")
}
return (
<div onClick={handleClick}>
<Child1 onClick={handleClick}/>
</div>
)
}
function Child({onClick}){
return (
<button onClick={(e)=>{
e.stopPropagation();
alert("Hello from Child");
onClick()
}}>Click me</button>
)
}
-> (1) Hello from Child
-> (2) Hello from Parent
Preventing Default Browser Behavior
In addition to propagation, there is another annoying event that you will definitely want to prevent.
When you submit a form by default the browser refreshes the page, therefore killing your entire React
application and probably causing some side effects like smashing your keyboard from anger when that happens.
function Form(){
function handleSubmit(e){
alert("Hello From Form")
}
return (
<form onSubmit={handleSubmit}>
<button>Submit</button>
</form>
)
}

So similarly to what we did to stop the propagation. All you need to do here is to go to the form’s onSubmit attached event handler, make sure to receive the e or event argument, then call the preventDefault
method on the e
object to prevent the default browser refresh behavior.
function Form(){
function handleSubmit(e){
e.preventDefault(); // This line prevents the browser's default behavior ✅
alert("Hello From Form")
}
return (
<form onSubmit={handleSubmit}>
<button>Submit</button>
</form>
)
}
Conclusion
Events are happening all the time in a highly interactive web application.
But when an event fires it’s usually handled by modifying some components in the React
application tree.
In the next article we will finally explore a fundamental concept that makes React
reacts and remembers what have happened now and in the past after some series of interactions or events.
Thank you for watching and happy coding 🧑💻.