React's own event system layered on top of the browser's native one.
React wraps native DOM events in a SyntheticEvent — a cross-browser wrapper that normalizes behavior so event handling works consistently regardless of the underlying browser. Historically, React attached a single listener at the document root and simulated bubbling internally for performance reasons rather than attaching a listener to every individual element; React 17 changed this to attach at the root container the app is rendered into instead of document, which specifically affects how multiple React roots on the same page interact with each other's events.
Event pooling — reusing a single SyntheticEvent object across events for performance — was removed in React 17 after causing a recurring class of confusing bugs, where accessing event properties asynchronously (inside a setTimeout, for instance) returned null because the pooled object had already been reused. Simpler mistakes are more common day to day: passing onClick={handleClick()} instead of onClick={handleClick} calls the function immediately during render instead of on click.
What you'll walk away knowing