Event handlers are functions that will be triggered in response to certain user actions, such as clicking a button, submitting a form, moving the mouse, typing in a text field, and so on.
For instance, consider the following example. Run the CodePen demo and click the button that says Click me. An alert box should pop up.
Open demo in new tab1<button onclick="success()">Click me</button>
In this case, we are using the onclick
attribute to set up an event handler for the <button>
element. When the button is clicked, the corresponding success()
function will be executed.
This code should look familiar to you, because it is the same example we used in the JavaScript Event Handling lesson.
Creating an event handler
We can do the same thing for JSX. Except, as we've mentioned before, the attributes in JSX should be written in camelCase, which means instead of onclick
, you need to use onClick
.
Button.jsx
1function Button() {
2 function handleClick() {
3 alert("Hello, World!");
4 }
5 return <button onClick={handleClick}>Click me</button>;
6}
7
8export default Button;
One thing to pay attention to is that you need to pass the handler function as a prop, remember to pass the function (onClick={handleClick}
) and not call the function (onClick={handleClick()}
), or it will be executed immediately when the webpage is loaded.
Alternatively, you can define event handlers directly inside the curly braces.
Button.jsx
1function Button() {
2 return (
3 <button
4 onClick={function handleClick() {
5 alert("Hello, World!");
6 }}>
7 Click me
8 </button>
9 );
10}
11
12export default Button;
Or you can use arrow functions to simplify things even further.
Button.jsx
1function Button() {
2 return (
3 <button
4 onClick={() => {
5 alert("Hello, World!");
6 }}>
7 Click me
8 </button>
9 );
10}
11
12export default Button;
Accessing props in event handler
Event handlers are functions define inside a component, so naturally, it will have access to props passed to that component. For example, let's modify our handleClick()
function to alert a message, which will be passed from the parent element as a prop.
AlertButton.jsx
1function AlertButton({ message }) {
2 function handleClick() {
3 alert(message);
4 }
5 return <button onClick={handleClick}>Click me</button>;
6}
7
8export default AlertButton;
App.jsx
1import AlertButton from "./components/AlertButton";
2
3export default function App() {
4 return <AlertButton message={"This message is passed from App.jsx"} />;
5}
Passing event handlers as props
Event handler functions can also be passed down to the child component as a prop. This technique is useful when your application follows a design system where functionality needs to be separate from styling. For instance,
Button.jsx
1function Button({ handler }) {
2 return (
3 <button onClick={handler} className=". . .">
4 Click me
5 </button>
6 );
7}
8
9export default Button;
This button contains styling, but notice that the event handler is not defined in the component, instead, it is passed down from the parent.
You can then define an AlertButton
:
AlertButton.jsx
1import Button from "./Button";
2
3function AlertButton({ message }) {
4 return (
5 <Button
6 handler={() => {
7 alert(message);
8 }}>
9 Click me
10 </Button>
11 );
12}
13
14export default AlertButton;
This AlertButton
acts as a wrapper for Button
. It will pass an event handler, providing functionality for the Button
.
And finally, the message can be passed from App.jsx.
1export default function App() {
2 return <AlertButton message={"This message is passed from App.jsx"} />;
3}
Seems like we are going through a lot of trouble just to create a button. But imaging you are creating a large scale project with different buttons for different purposes.
For example, you could have an alert button, an upload button, a theme switcher button and more. These buttons need to have uniform style, but different functionality and different event handler function.
Separating styles from function means when you need to change the button styling, it is no longer necessary to go though every button component.
Event propagation
Just like in plain JavaScript, events will propagate from the child to the parent node. For example, as we've demonstrated in the JavaScript event handling lesson:
Open demo in new tabWhen you click on the button, that click event will propagate from <button>
, to <p>
, and finally reaches <div>
and gets picked up by the event handler clicked()
.
The same rules apply when you use React and JSX. For instance,
1export default function App() {
2 return (
3 <div
4 onClick={() => {
5 alert("Div clicked!");
6 }}>
7 <p
8 onClick={() => {
9 alert("Paragraphed clicked!");
10 }}>
11 <button
12 onClick={() => {
13 alert("Button clicked!");
14 }}>
15 Click me
16 </button>
17 </p>
18 </div>
19 );
20}
When you click the button, the event will propagate from <button>
, to <p>
, and finally reaches <div>
.
Stop event propagation
As the event propagates, details regarding that event will be passed along as an object, which can be access in the event handler function. For example, when a click
event is fired, you can find out exact which mouse button was clicked like this:
1export default function App() {
2 return (
3 <div
4 onClick={() => {
5 alert("Div clicked!");
6 }}>
7 <p
8 onClick={(event) => {
9 console.log(event.button); // <=========
10 alert("Paragraphed clicked!");
11 }}>
12 <button
13 onClick={() => {
14 alert("Button clicked!");
15 }}>
16 Click me
17 </button>
18 </p>
19 </div>
20 );
21}
The event object comes with a stopPropagation()
method that can be used to stop an event from propagating. Consider the following example,
1export default function App() {
2 return (
3 <div
4 onClick={() => {
5 alert("Div clicked!");
6 }}>
7 <p
8 onClick={(event) => {
9 event.stopPropagation(); // <=========
10 alert("Paragraphed clicked!");
11 }}>
12 <button
13 onClick={() => {
14 alert("Button clicked!");
15 }}>
16 Click me
17 </button>
18 </p>
19 </div>
20 );
21}
The click
event will be stopped from propagating at <p>
, and the event handler at <div>
will not be activated.
Prevent default event action
Certain events have default actions, for example, when you right click on the webpage, the context menu will be opened. If you want to change that behavior, use the preventDefault()
method to stop the default action from being triggered.
1export default function App() {
2 return (
3 <div
4 onContextMenu={(event) => {
5 event.preventDefault(); // <=========
6 alert("Hello, World!");
7 }}
8 className="w-20">
9 Lorem ipsum...
10 </div>
11 );
12}
And now, when you right click on this <div>
element, instead of opening the context menu, an alert box will be triggered.