AniUI Academy

Web-Aligned Event Dispatching

Native event dispatch is being reshaped to match the DOM: capture and bubble phases, a composed event path, pointer events, and stopPropagation with the semantics you already know.

9 min read

React Native's touch and gesture handling has historically been its own system — the "responder" model — with its own rules about who captures a touch, how it can be stolen, and what cancellation looks like. That model worked, but it never quite matched the DOM events most of its users already knew. The platform has been quietly closing that gap for a few releases now, and in current versions the native event dispatcher is designed to behave the same way a browser's does. This lesson is about what that means in practice.

The old shape, in one paragraph

Classic React Native dispatched touches through a responder negotiation: components could claim to be the responder for a given touch, pass it to parents or children, and lose it mid-gesture if another component "stole" it. It was powerful, but the rules were idiosyncratic and didn't map onto any model outside React Native itself. If you learned DOM events first (and most people do), you had to unlearn them to debug a nested scroll-plus-swipe-plus-tap bug.

The shape events take now

The direction set by the platform is that events flow through the same two-phase model the DOM uses:

  1. Step 1

    Capture phase

    Listeners along the path from the root to the event target fire first, top-down. An ancestor can observe, log, or stopPropagation before the target ever sees the event.

  2. Step 2

    Target

    The deepest component the event is aimed at receives it. In most apps, this is the handler you wrote on the component the user actually touched.

  3. Step 3

    Bubble phase

    Listeners fire again from the target back up to the root. A parent Pressable's onPress runs after the child's — unless something along the way stops propagation.

The event object also gains the shape you'd recognise from the web: event.target, event.currentTarget, event.composedPath() (returning the list of components the event is travelling through), and the cancellation methods stopPropagation() and preventDefault() with their familiar semantics. Pointer-style events — pointerdown, pointermove, pointerup — are the first-class way the platform expresses "a thing touched the screen, moved, lifted," unifying touch, mouse, and pen input under one API, exactly like PointerEvent on the web.

The two concrete reasons this matters

The first is shared code. A gesture-handling library, a form library, an accessibility tool — anything that cares about event dispatch — can now share one implementation across web and native. React Native for Web projects benefit obviously; cross-platform component libraries benefit even if you don't ship to web yourself, because the libraries you depend on have fewer forks to maintain, which translates to fewer platform- specific bugs for you to work around.

The second is a mature spec to lean on. The DOM event model has been specified, documented, and debugged by the web community for two decades. When an edge case comes up — "what happens if I call preventDefault inside a passive listener?", "does focus move before or after click?", "how does pointer capture interact with removal from the DOM?" — there's a published answer rather than an empirical "try it and see." React Native inheriting that spec is cheaper than maintaining its own version of the same answers, and it means fewer undocumented quirks you have to discover by hitting them in production.

What this changes in your own component code

For the common case — one Pressable, one onPress, done — nothing changes. The simple handler you've always written still works the same way.

Where it changes is anywhere you previously needed the responder system to do something intricate:

  • Nested interactive components become easier. A Pressable inside a scrollable parent inside a modal follows the capture / bubble rules you already know. You stop writing responder-negotiation code and start writing the same stopPropagation() you'd write on the web.
  • Pointer-based gestures have a standard API. Custom drag, hover (on platforms that support it), and pen interactions don't need a separate "is this a mouse, a touch, or a stylus?" branch — the pointer event tells you, through the same pointerType field a browser would use.
  • Accessibility and focus events become more consistent. Focus, blur, and key events behave as the DOM specifies, which matches what assistive-technology APIs on both platforms expect.

When the two models meet

The responder system hasn't vanished overnight — existing libraries still depend on it, and the platform has been careful to keep them working. In practice, that means code written against the old touch responder API continues to function, and new code gets the web-aligned model. The migration is gradual and the failure mode of mixing the two in one app is "an occasional edge case where the two systems disagree" rather than "nothing works." As with the New Architecture itself, the useful skill is knowing the new model exists and reaching for it when writing new gesture-heavy code, not rewriting every existing PanResponder in the app the day a new release lands.

What to remember

  • Native event dispatching is being aligned with the W3C UI Events model: capture → target → bubble, composedPath, stopPropagation/preventDefault with DOM semantics, and first-class pointer events.
  • The same mental model you use for DOM events now applies to native events. Nested interactive components become predictable without responder-negotiation code.
  • Two concrete payoffs: cross-platform libraries can share one event implementation, and the DOM spec answers edge cases that previously required empirical discovery.
  • Day-to-day component code (one Pressable, one onPress) is unchanged. The savings show up in gesture-heavy and cross-platform work.
  • The legacy touch-responder system hasn't disappeared — existing code keeps working. The migration is gradual, and the new model is the one to reach for in new code.

Check yourself

4 questions · pass 3/4 to unlock TextInput and Forms

up to 50
  1. 1.What does the phrase 'web-aligned event dispatching' actually mean in React Native's context?

  2. 2.Under the aligned model, what order do listeners along the path from the root to the target actually fire in?

  3. 3.A parent Pressable wraps a child Pressable. The user presses the child. How does stopPropagation() in the child's handler affect the parent?

  4. 4.Why does aligning native event dispatch with the web model matter beyond 'it feels familiar'?

4 left to answer

Discussion

Sign in to post
Sign in to join the conversation.Sign in

No comments yet. Be the first to say something.