Events and forms
Understand event propagation
Recognize that nested event handlers can both run and stop propagation only when the interaction should not reach an ancestor.
Browser events normally bubble from the target through its ancestors.
function TaskRow() {
return (
<article onClick={() => console.log('Open task')}>
<h2>Update the docs</h2>
<button onClick={() => console.log('Delete task')}>
Delete
</button>
</article>
)
}
Click Delete and the console prints Delete task, then Open task. That may open a task while deleting it.
If the interactions are intentionally separate, stop propagation in the nested handler:
function handleDelete(event) {
event.stopPropagation()
deleteTask()
}
After stopPropagation(), only Delete task appears in the console.
Use this deliberately. Global propagation blocking can break analytics, keyboard behavior, and parent-level event handling.
Often the better design is not to make the entire container clickable. Use a real link for navigation and a separate button for deletion. Clear semantics can remove the propagation conflict.
preventDefault() solves another problem. It prevents the browser’s default action, such as form navigation or following a link. It does not stop the event from reaching ancestors.
In React’s synthetic event system, stopPropagation() still prevents ancestor handlers in your React tree from running. Test the behavior you want rather than assuming the browser default matches your layout.
Capture phase is the opposite direction: the event travels from the root down to the target before bubbling back up. React exposes onClickCapture when you need that path, but most UI code only needs bubbling.
Portal content still participates in React’s event tree even when the DOM node lives elsewhere, so propagation rules still apply inside your components.
Test card layouts with a delete button inside a clickable row. That pattern shows up often in task lists and admin tables.
Log event.target and event.currentTarget in both handlers. The target is where the event began. The current target is the element whose handler is running.
Lesson completed