React Event Object Properties: Complete Guide
Every event handler in React receives a SyntheticEvent object as its first argument—a goldmine of information about what the user just did. Understanding the event object's key properties like event.target, event.target.value, and event.stopPropagation() lets you build flexible form handlers, read input values, and control how events flow through your component tree.
Key Takeaways
- Every React event handler receives a
SyntheticEventobject (usually namede) containing information about the user's interaction event.targetreferences the DOM element that triggered the event (the input the user typed in, the button they clicked)event.target.valuereads the current value from an input or textarea;event.target.checkedreads a checkbox's state- The "one handler for multiple inputs" pattern using
event.target.nameand a singlehandleChangefunction eliminates repetitive code in large forms event.stopPropagation()prevents an event from bubbling up to parent elements, essential for nested clickable components
The Event Object: Core Concept
When a user interacts with an element (clicking, typing, hovering), React passes your event handler a SyntheticEvent object. This object wraps the browser's native event and provides a consistent API across all browsers, eliminating cross-browser compatibility issues.
The most useful property on the event object is target: the DOM element where the event originated. If a user clicks a button, event.target is that button. If they type in an input, event.target is that input.
function MyButton() {
function handleClick(e) {
console.log(e); // The SyntheticEvent object
console.log(e.target); // The <button> DOM element
}
return <button onClick={handleClick}>Click Me</button>;
}
Reading Input Values with event.target.value
The most common use case for the event object is capturing what a user typed into an input field. Here's the fundamental pattern:
import React, { useState } from 'react';
export default function NameForm() {
const [name, setName] = useState('');
function handleChange(e) {
const newValue = e.target.value;
setName(newValue);
}
return (
<>
<label>Name: </label>
<input value={name} onChange={handleChange} />
<p>Your name is: {name}</p>
</>
);
}
How it works:
- User types into the input
onChangeevent fires, callinghandleChange(e)e.targetis the input element;e.target.valueis what the user typedsetName()updates state with the new value- Component re-renders; the input now shows the updated value
This pattern—where state controls the input's value—is called a controlled component. React is the single source of truth for the input's current value, allowing you to validate, format, or modify the input before storing it.
Advanced Pattern: One Handler for Multiple Inputs
With many form fields, writing a separate handler for each becomes repetitive:
// Repetitive approach (don't do this)
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const handleFirstNameChange = (e) => setFirstName(e.target.value);
const handleLastNameChange = (e) => setLastName(e.target.value);
const handleEmailChange = (e) => setEmail(e.target.value);
Instead, combine all form data into one state object and use a single generic handler:
import React, { useState } from 'react';
export default function SignupForm() {
const [formState, setFormState] = useState({
firstName: '',
lastName: '',
email: '',
});
function handleChange(e) {
const { name, value } = e.target;
setFormState(prevState => ({
...prevState,
[name]: value
}));
}
return (
<form>
<input
name="firstName"
value={formState.firstName}
onChange={handleChange}
placeholder="First Name"
/>
<input
name="lastName"
value={formState.lastName}
onChange={handleChange}
placeholder="Last Name"
/>
<input
name="email"
value={formState.email}
onChange={handleChange}
placeholder="Email"
/>
</form>
);
}
How it works:
- All form data lives in one
formStateobject - Each input has a
nameattribute matching its corresponding state property (firstName,lastName,email) - All inputs call the same
handleChangehandler - Inside the handler, destructure
nameandvaluefrom the event target - Use computed property syntax
[name]: valueto update the correct state field
This pattern reduces boilerplate dramatically. The handler works for any number of inputs without modification.
Handling Checkboxes
For checkboxes, use event.target.checked instead of event.target.value:
const [formState, setFormState] = useState({
email: '',
agreeToTerms: false,
});
function handleChange(e) {
const { name, type, value, checked } = e.target;
const newValue = type === 'checkbox' ? checked : value;
setFormState(prevState => ({
...prevState,
[name]: newValue
}));
}
return (
<>
<input name="email" type="text" value={formState.email} onChange={handleChange} />
<input
name="agreeToTerms"
type="checkbox"
checked={formState.agreeToTerms}
onChange={handleChange}
/>
</>
);
The handler now checks type === 'checkbox' and uses checked for checkboxes, value for text inputs.
Controlling Event Propagation
Events in React (like the browser) bubble up from child elements to parents. When you click a button inside a div, both the button's onClick and the div's onClick fire.
Use event.stopPropagation() to stop an event from reaching parent elements:
function ChildButton({ onClick }) {
function handleClick(e) {
e.stopPropagation(); // Stop bubbling to parent
onClick();
}
return <button onClick={handleClick}>Click Me</button>;
}
function Parent() {
return (
<div onClick={() => alert('Parent div clicked!')}>
<ChildButton onClick={() => alert('Child button clicked!')} />
</div>
);
}
When you click the button, only "Child button clicked!" appears. The stopPropagation() call prevents the click event from ever reaching the parent div's onClick handler.
Essential Event Object Properties
Here are the most important properties and methods on a SyntheticEvent:
| Property/Method | Use Case | Example |
|---|---|---|
event.target | Reference to the element that triggered the event | const input = e.target; |
event.target.value | Read text input or textarea value | const text = e.target.value; |
event.target.checked | Read checkbox or radio button state | const isChecked = e.target.checked; |
event.target.name | Read the name attribute (for form handling) | const fieldName = e.target.name; |
event.preventDefault() | Prevent default behavior (e.g., form submission) | e.preventDefault(); |
event.stopPropagation() | Stop event bubbling to parent elements | e.stopPropagation(); |
event.type | String describing the event type | event.type === 'click' |
Example: Complete Form with Validation
Here's a realistic form that demonstrates all concepts:
import React, { useState } from 'react';
export default function UserForm() {
const [formState, setFormState] = useState({
username: '',
password: '',
rememberMe: false,
});
const [errors, setErrors] = useState({});
function handleChange(e) {
const { name, type, value, checked } = e.target;
const newValue = type === 'checkbox' ? checked : value;
setFormState(prevState => ({
...prevState,
[name]: newValue
}));
// Clear error for this field when user starts correcting it
if (errors[name]) {
setErrors(prev => ({
...prev,
[name]: ''
}));
}
}
function handleSubmit(e) {
e.preventDefault(); // Stop form from refreshing page
const newErrors = {};
if (formState.username.length === 0) newErrors.username = 'Username required';
if (formState.password.length === 0) newErrors.password = 'Password required';
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
return;
}
console.log('Form submitted:', formState);
}
return (
<form onSubmit={handleSubmit}>
<div>
<input
name="username"
type="text"
value={formState.username}
onChange={handleChange}
placeholder="Username"
/>
{errors.username && <span style={{ color: 'red' }}>{errors.username}</span>}
</div>
<div>
<input
name="password"
type="password"
value={formState.password}
onChange={handleChange}
placeholder="Password"
/>
{errors.password && <span style={{ color: 'red' }}>{errors.password}</span>}
</div>
<label>
<input
name="rememberMe"
type="checkbox"
checked={formState.rememberMe}
onChange={handleChange}
/>
Remember me
</label>
<button type="submit">Login</button>
</form>
);
}
This form demonstrates: one state object, one handler for all inputs, validation on submit, and e.preventDefault() to stop the page from refreshing.
Frequently Asked Questions
What is the difference between SyntheticEvent and a native browser event?
React wraps browser events in a SyntheticEvent object for consistency. This means the same code works across all browsers—IE, Chrome, Firefox—without worrying about browser-specific quirks. React handles the cross-browser differences behind the scenes. For 99% of cases, you don't notice the difference; the API is identical.
Can I access the event object asynchronously after the handler finishes?
No. React reuses SyntheticEvent objects for performance reasons. After your handler completes, the event object is recycled and its properties become null. If you need to access event properties asynchronously, copy them to variables first:
function handleChange(e) {
const value = e.target.value; // Copy to variable
setTimeout(() => console.log(value), 1000); // Use the variable, not e
}
When should I use event.preventDefault()?
Call preventDefault() on events whose default browser behavior you want to block. Common cases: form submission (to handle it with JavaScript), link clicks (to handle with React Router), and keyboard events. Without it, a form will refresh the page on submit.
Why does my checkbox not update when I click it?
Make sure you're using checked={formState.fieldName} for checkboxes, not value. Also ensure your handler checks type === 'checkbox' and reads the checked property. For a text input, use value; for checkboxes/radio buttons, use checked.
Can I stop event propagation conditionally?
Yes. For example, only stop propagation if the user meets a condition:
function handleClick(e) {
if (userHasPermission) {
e.stopPropagation();
}
onClick();
}
Further Reading
Deepen your understanding of React events and form handling:
Glossary
SyntheticEvent: React's cross-browser wrapper around the native browser event object, providing a consistent API.
event.target: Property referring to the DOM element that dispatched the event (the input typed in, button clicked, etc.).
Controlled Component: A form input whose value is controlled by React state, making React the single source of truth.
Event Propagation (Bubbling): Process where an event travels from a target element up through its parent elements in the DOM tree.
Computed Property Name: JavaScript syntax [variableName]: value that uses a variable's content as an object property key.
preventDefault(): Event method that stops the browser's default action for an event (e.g., form submission refreshing the page).