When an event happens, React passes an event object to your handler function. This object contains valuable information about what happened - which key was pressed, where the mouse was clicked, what the input value is, and much more. Understanding event objects unlocks advanced interactivity patterns like preventing default behaviors, stopping event bubbling, and accessing detailed event data. Let's explore everything you can do with event objects!
The Event Object
Every event handler receives an event object as its first parameter:
function Example() {
const handleClick = (event) => {
console.log('Event object:', event)
console.log('Event type:', event.type)
console.log('Target element:', event.target)
console.log('Current target:', event.currentTarget)
}
return <button onClick={handleClick}>Click Me</button>
}
// When you click the button, you'll see:
// Event object: SyntheticBaseEvent { ... }
// Event type: "click"
// Target element: <button>Click Me</button>
// Current target: <button>Click Me</button>Common Event Object Properties:
event.type- Type of event ("click", "change", etc.)event.target- Element that triggered the eventevent.currentTarget- Element with the event handlerevent.preventDefault()- Prevent default behaviorevent.stopPropagation()- Stop event bubbling
Synthetic Events
React doesn't give you native browser events. Instead, it wraps them in SyntheticEvent objects:
function Example() {
const handleClick = (event) => {
console.log(event) // SyntheticBaseEvent, not MouseEvent
// Synthetic events have the same interface as native events
console.log(event.type) // Works
console.log(event.target) // Works
console.log(event.preventDefault) // Works
// But they're NOT native events
console.log(event instanceof MouseEvent) // false
}
return <button onClick={handleClick}>Click</button>
}
// React creates synthetic events for cross-browser compatibilityWhy Synthetic Events?
- Cross-browser compatibility - Same API everywhere
- Performance - React pools and reuses event objects
- Consistency - Events work the same in all browsers
- Extra features - React adds helpful properties
Accessing Native Events:
If you need the native browser event, access it via event.nativeEvent. But you rarely need this - synthetic events have everything you need!
target vs currentTarget
Two similar but different properties that often confuse beginners:
function Example() {
const handleClick = (event) => {
console.log('target:', event.target) // Element clicked
console.log('currentTarget:', event.currentTarget) // Element with handler
}
return (
<div onClick={handleClick}>
{/* div has the onClick handler */}
<button>Click Me</button>
<p>Or click this text</p>
</div>
)
}
// If you click the button:
// target: <button>Click Me</button> (what you clicked)
// currentTarget: <div>...</div> (where handler is attached)
// If you click the paragraph:
// target: <p>Or click this text</p> (what you clicked)
// currentTarget: <div>...</div> (where handler is attached)
// currentTarget is always the same (the div)
// target changes based on what you actually clicked🤔 Which One to Use?
Use event.target when:
• You want to know which specific element was clicked
• You need the value from the exact input that changed
Use event.currentTarget when:
• You want the element that has the event handler
• You're delegating events to a parent element
Most of the time, you'll use event.target
preventDefault()
Prevents the browser's default behavior for an event:
Form Submission
function LoginForm() {
const handleSubmit = (event) => {
event.preventDefault() // Prevent page reload!
console.log('Form submitted')
// Handle submission with JavaScript
}
return (
<form onSubmit={handleSubmit}>
<input type="email" placeholder="Email" />
<button type="submit">Login</button>
</form>
)
}
// Without preventDefault(), form submission would:
// 1. Send data to server
// 2. Reload the page
// 3. Lose all React state
// With preventDefault(), you handle it with JavaScriptLink Navigation
function CustomLink() {
const handleClick = (event) => {
event.preventDefault() // Prevent navigation!
console.log('Link clicked, but not navigating')
// Do something custom instead
}
return (
<a href="https://example.com" onClick={handleClick}>
Click me (won't navigate)
</a>
)
}
// Without preventDefault(), clicking the link would navigate away
// With preventDefault(), you control what happensContext Menu
function CustomContextMenu() {
const handleContextMenu = (event) => {
event.preventDefault() // Prevent default right-click menu
console.log('Custom context menu')
// Show your own custom menu
}
return (
<div onContextMenu={handleContextMenu}>
Right-click me to see custom behavior
</div>
)
}Drag and Drop
function DropZone() {
const handleDrop = (event) => {
event.preventDefault() // Allow drop!
console.log('File dropped')
}
const handleDragOver = (event) => {
event.preventDefault() // Must prevent default to allow drop
}
return (
<div
onDrop={handleDrop}
onDragOver={handleDragOver}
style={{ border: '2px dashed gray', padding: '20px' }}
>
Drop files here
</div>
)
}stopPropagation()
Stops the event from bubbling up to parent elements:
Event Bubbling Explained
function Example() {
const handleDivClick = () => {
console.log('Div clicked')
}
const handleButtonClick = () => {
console.log('Button clicked')
}
return (
<div onClick={handleDivClick}>
<button onClick={handleButtonClick}>
Click Me
</button>
</div>
)
}
// When you click the button:
// Console output:
// "Button clicked" (button handler runs first)
// "Div clicked" (then bubbles up to div)
// The event travels UP the DOM tree - this is called "bubbling"Stopping Propagation
function Example() {
const handleDivClick = () => {
console.log('Div clicked')
}
const handleButtonClick = (event) => {
event.stopPropagation() // Stop bubbling!
console.log('Button clicked')
}
return (
<div onClick={handleDivClick}>
<button onClick={handleButtonClick}>
Click Me
</button>
</div>
)
}
// When you click the button:
// Console output:
// "Button clicked" (button handler runs)
// (div handler never runs - propagation stopped!)
// The event doesn't bubble up to the divPractical Example: Modal with Backdrop
function Modal({ onClose }) {
const handleBackdropClick = () => {
onClose() // Close modal when backdrop is clicked
}
const handleContentClick = (event) => {
event.stopPropagation() // Don't close when content is clicked
}
return (
<div className="modal-backdrop" onClick={handleBackdropClick}>
<div className="modal-content" onClick={handleContentClick}>
<h2>Modal Title</h2>
<p>Click outside to close, click inside to stay open</p>
<button onClick={onClose}>Close</button>
</div>
</div>
)
}
// Without stopPropagation:
// Clicking inside modal would bubble to backdrop and close modal
// With stopPropagation:
// Clicking inside modal stops event from reaching backdropUse stopPropagation() Sparingly:
Event bubbling is usually helpful! Only stop propagation when you have a specific reason. Common valid uses:
• Modal/dialog backdrops
• Nested clickable elements
• Dropdown menus
Overusing stopPropagation() can make your code harder to debug.
Accessing Event Data
Input Values
function Form() {
const handleChange = (event) => {
console.log('Input value:', event.target.value)
console.log('Input name:', event.target.name)
console.log('Input type:', event.target.type)
}
return (
<input
type="text"
name="username"
onChange={handleChange}
placeholder="Username"
/>
)
}
// event.target gives you the input element
// You can access any property: value, name, type, placeholder, etc.Checkbox and Radio
function CheckboxExample() {
const handleChange = (event) => {
console.log('Checked:', event.target.checked) // true or false
console.log('Value:', event.target.value)
console.log('Name:', event.target.name)
}
return (
<>
<input
type="checkbox"
name="subscribe"
value="newsletter"
onChange={handleChange}
/>
<input
type="radio"
name="size"
value="large"
onChange={handleChange}
/>
</>
)
}
// For checkboxes/radio: use event.target.checked (not .value)Mouse Position
function MouseTracker() {
const handleMouseMove = (event) => {
console.log('Mouse X:', event.clientX)
console.log('Mouse Y:', event.clientY)
console.log('Page X:', event.pageX)
console.log('Page Y:', event.pageY)
console.log('Screen X:', event.screenX)
console.log('Screen Y:', event.screenY)
}
return (
<div onMouseMove={handleMouseMove}>
Move mouse here
</div>
)
}
// Different coordinate systems:
// clientX/Y - relative to viewport
// pageX/Y - relative to document (includes scroll)
// screenX/Y - relative to screenKeyboard Keys
function KeyboardTracker() {
const handleKeyDown = (event) => {
console.log('Key:', event.key) // 'a', 'Enter', 'ArrowUp'
console.log('Key code:', event.keyCode) // Deprecated
console.log('Code:', event.code) // 'KeyA', 'Enter', 'ArrowUp'
// Modifier keys
console.log('Shift pressed:', event.shiftKey)
console.log('Ctrl pressed:', event.ctrlKey)
console.log('Alt pressed:', event.altKey)
console.log('Meta pressed:', event.metaKey) // Cmd on Mac, Win on Windows
}
return (
<input
type="text"
onKeyDown={handleKeyDown}
placeholder="Press keys..."
/>
)
}
// event.key is what you usually want
// It gives you the actual key pressedFile Upload
function FileUpload() {
const handleChange = (event) => {
const files = event.target.files // FileList object
if (files.length > 0) {
const file = files[0] // First file
console.log('File name:', file.name)
console.log('File size:', file.size)
console.log('File type:', file.type)
console.log('Last modified:', file.lastModified)
}
}
return (
<input
type="file"
onChange={handleChange}
multiple // Allow multiple files
/>
)
}
// event.target.files contains all selected filesInteractive Demo
💡 Tip: Edit the code above and click "Run" to see your changes
Common Event Object Patterns
Pattern 1: Extracting Multiple Properties
function Form() {
const [formData, setFormData] = React.useState({})
const handleChange = (event) => {
const { name, value, type, checked } = event.target
setFormData({
...formData,
[name]: type === 'checkbox' ? checked : value
})
}
return (
<form>
<input name="username" onChange={handleChange} />
<input name="email" type="email" onChange={handleChange} />
<input name="subscribe" type="checkbox" onChange={handleChange} />
</form>
)
}
// Destructure commonly needed properties at the startPattern 2: Conditional preventDefault
function Form() {
const [isValid, setIsValid] = React.useState(false)
const handleSubmit = (event) => {
if (!isValid) {
event.preventDefault() // Only prevent if invalid
alert('Please fix errors first')
}
// If valid, allow default behavior or handle it
}
return (
<form onSubmit={handleSubmit}>
{/* form fields */}
</form>
)
}Pattern 3: Key Combinations
function Editor() {
const handleKeyDown = (event) => {
// Save: Ctrl+S or Cmd+S
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
event.preventDefault()
console.log('Save triggered')
}
// Undo: Ctrl+Z or Cmd+Z
if ((event.ctrlKey || event.metaKey) && event.key === 'z') {
event.preventDefault()
console.log('Undo triggered')
}
}
return <textarea onKeyDown={handleKeyDown} />
}
// Check modifier keys for keyboard shortcutsKey Takeaways
- Event handlers receive a SyntheticEvent object
- Synthetic events work identically across all browsers
event.targetis the element that triggered the eventevent.currentTargetis the element with the handlerevent.preventDefault()stops default browser behavior- Always use preventDefault() in onSubmit handlers
event.stopPropagation()stops event bubbling- Use stopPropagation() sparingly (modals, nested clicks)
- Access input values with
event.target.value - Access checkbox state with
event.target.checked - Get keyboard info with
event.keyand modifier keys - Mouse position available via clientX/Y, pageX/Y, screenX/Y
- Events bubble up the DOM tree by default
What's Next?
You now understand event objects in depth! You know how to prevent default behaviors, stop event propagation, and access all kinds of event data.
Now it's time to put this knowledge to work building real forms. In the next lesson, you'll learn about Forms in React:
- Creating controlled form components
- Handling multiple form inputs
- Building complex forms efficiently
- Form state management patterns
- Common form patterns and best practices
Get ready to master React forms! 📝