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>
  )
}

Clicking Delete runs the button handler, then the article handler. 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()
}

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.

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

Take this course offline

Get every free book, course edition, and software download.

Get the download library →