Skip to content

Lib: fix onbeforeunload handler breaking navigation (#1436) #2159

Open
hhugo wants to merge 3 commits into
masterfrom
fixunloadevent
Open

Lib: fix onbeforeunload handler breaking navigation (#1436) #2159
hhugo wants to merge 3 commits into
masterfrom
fixunloadevent

Conversation

@hhugo
Copy link
Copy Markdown
Member

@hhugo hhugo commented Feb 3, 2026

Summary

Fixes #1436.

Dom.handler converts the OCaml bool t return value to a JavaScript return value. When a beforeunload handler returns Js._true (allow navigation), the JS value true is passed to the browser. Modern browsers interpret any non-null, non-undefined return value from a beforeunload handler as a request to show the "Leave page?" confirmation dialog. This means that even when the OCaml handler intended to allow navigation, the browser would show a blocking dialog.

Changes

The fix detects beforeunload events at runtime in Dom.handler and Dom.full_handler:

  • When the handler returns Js._true (allow navigation), return undefined to the browser instead of true, so no dialog is shown.
  • When the handler returns Js._false (block navigation), also set event.returnValue = "" for legacy browser compatibility.
  • In Dom.invoke_handler, normalize undefined back to Js._true so callers that chain handlers still see a proper bool t value.

Also adds Dom.beforeUnloadEvent and Dom_html.beforeUnloadEvent class types with the returnValue property, and types onbeforeunload to use beforeUnloadEvent instead of the generic event type.

@hhugo hhugo force-pushed the fixunloadevent branch 2 times, most recently from c3936a5 to ea37016 Compare February 4, 2026 16:20
@hhugo
Copy link
Copy Markdown
Member Author

hhugo commented Feb 5, 2026

@TyOverby, this PR breaks some virtual_dom tests. Can you comment maybe ?

@hhugo
Copy link
Copy Markdown
Member Author

hhugo commented Feb 13, 2026

@vouillon, any though ?

@hhugo hhugo force-pushed the fixunloadevent branch 2 times, most recently from d0b8fdb to 5f1dfc6 Compare May 11, 2026 11:37
hhugo and others added 3 commits May 11, 2026 16:07
All modern browsers show a confirmation dialog when the beforeunload
handler returns any value other than null or undefined. Dom.handler
returned Js._true as the JS value true, which incorrectly triggered
the dialog even when the handler intended to allow navigation.

Fix by detecting beforeunload events at runtime in Dom.handler and
Dom.full_handler: Js._true returns undefined to JS (allowing
navigation without a dialog), while Js._false continues to call
preventDefault and also sets event.returnValue for legacy browsers.
Dom.invoke_handler normalizes undefined back to Js._true.

Also adds Dom.beforeUnloadEvent and Dom_html.beforeUnloadEvent class
types with the returnValue property, and types onbeforeunload to use
beforeUnloadEvent instead of the generic event type.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Js.Unsafe.pure_js_expr returns a JS value, not an OCaml function, so the
previous form could not call the predicate.  Use Js.Unsafe.fun_call to
invoke it with the event as argument.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hhugo hhugo force-pushed the fixunloadevent branch from d30cb17 to f61f327 Compare May 11, 2026 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] semantics of (onbeforeunload, Dom_html.handler) incompatible with major browsers

1 participant