Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize beforeunload event information #29595

Merged
merged 6 commits into from
Oct 12, 2023

Conversation

chrisdavidmills
Copy link
Contributor

Description

Chrome 119 includes an update to the beforeunload event — it now triggers the "leave page?" confirmation dialog when e.preventDefault() is called upon the event firing, and doesn't do that when e.returnValue is set to an empty string. This is great because Chrome now behaves like other browsers, so this event is immediately more useful than it was.

This PR:

  • Brings the corresponding MDN content up-to-date, telling a clearer story about the state of the platform now.
  • Adds better, clearer examples.
  • Modernizes page structures, makes them more consistent with the rest of the site.
  • Reduces repetition and generally makes the content easier to follow.

Also related:

Motivation

Additional details

Related issues and pull requests

@chrisdavidmills chrisdavidmills requested a review from a team as a code owner October 11, 2023 13:13
@chrisdavidmills chrisdavidmills requested review from wbamberg and removed request for a team October 11, 2023 13:13
@github-actions github-actions bot added the Content:WebAPI Web API docs label Oct 11, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Oct 11, 2023

Preview URLs

External URLs (3)

URL: /en-US/docs/Web/API/Window/beforeunload_event
Title: Window: beforeunload event

(comment last updated: 2023-10-12 08:18:11)

- {{domxref("SVGSVGElement")}}

## Security
- Only show the dialog box if the frame or any embedded frame receives a user gesture or user interaction.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not that clear what this means and how it differs from sticky activation (the third condition). I understand the sticky activation requirement (and think it is maybe worth spelling out: the point being that if the user has never interacted with the page, then there is no user data to save, so no legitimate use case for the dialog).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I was supposed to merge those into one point as they are basically the same thing. I've done that in my next commit, as well as adding your thought about "if the user has never interacted..."; I think that is useful. Thanks!

Comment on lines 45 to 46
event.returnValue = "any non-empty string value";
// Equivalent to invoking event.preventDefault();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this example should be showing the non-recommended version (setting returnValue).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you're right. I've updated it to show the same example as on the event page, and I've added a note at the bottom of the section to say that the returnValue property can also be used, but it is legacy and not best practice.

Comment on lines +52 to +56
if (event.target.value !== "") {
window.addEventListener("beforeunload", beforeUnloadHandler);
} else {
window.removeEventListener("beforeunload", beforeUnloadHandler);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add/remove listeners on input, rather than always have the beforeunload listener, but conditionally call preventDefault() based on the value of target? It seems like that would be more efficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reasons explained in the "Usage notes" section of the event page, most critically the one about Firefox not placing pages in the bfcache if they have beforeunload listeners.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I just realised this. Maybe worth mentioning in the description of this example to save other people from making my mistake!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call; done.


The `beforeunload` event is fired when the window, the document and its resources are about to be unloaded.
The `returnValue` property defined on `BeforeUnloadEvent`, when set to a non-empty string value, triggers a browser-generated confirmation dialog. This dialog asks users to confirm if they _really_ want to leave the page when they try to close or reload it, or navigate somewhere else. It is intended to help prevent loss of unsaved data.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sort of see the point of describing this property here, but I think it would be better just to describe it in the returnValue page, and adapt the note slightly like:

> **Note:** The `returnValue` property of this interface is...

Otherwise it looks a bit odd that you are going to special lengths to describe this property in this paragraph, then undercutting it immediately in the note.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I've removed most of this text, making sure it is covered in the returnValue page itself, and added a note about it being legacy to the returnValue description on the BeforeUnloadEvent page. This seemed like a better place for it to go.


## Value

`returnValue` is initiailized to an empty string (`""`) value.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`returnValue` is initiailized to an empty string (`""`) value.
`returnValue` is initialized to an empty string (`""`) value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in next commit; thanks!


`returnValue` is initiailized to an empty string (`""`) value.

Setting it to just about any [truthy](/en-US/docs/Glossary/Truthy) value will cause the dialog to be triggered on page close/reload.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth repeating or linking to the extra conditions (e.g. sticky activation) or this will mislead people.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I've added this info to the returnValue page.

Copy link

@dizhang168 dizhang168 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really good, thanks for updating the docs! My concern is that there is no mention of the return "non-empty string" pattern, which is likely still used by a lot of web developers.

The HTML specification states that calls to {{domxref("window.alert()")}}, {{domxref("window.confirm()")}}, and {{domxref("window.prompt()")}} methods may be ignored during this event. See the [HTML specification](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#user-prompts) for more details.
- Calling the event object's {{domxref("Event.preventDefault()", "preventDefault()")}} method.
- Setting the event object's {{domxref("BeforeUnloadEvent.returnValue", "returnValue")}} property to a non-empty string value.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that returning a value (e.g. "return "Not empty string") will also trigger the cancel dialog. However, that behavior is weird as it doesn't work on addEventListener, but does work on onbeforeunload. It is a legacy behavior and should still be mentioned on the docs.

You can read more context at crbug.com/809277.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good call, thank you! I have mentioned this now, both in the list of methods for triggering the dialog, and in a comment in the code example.

Copy link
Collaborator

@wbamberg wbamberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thank you Chris! Approving but leaving open in case @dizhang168 wants to verify that their comments are addressed. But this is good as far as I am concerned.

Copy link

@dizhang168 dizhang168 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! (can't approve as I am not a repo owner)

@wbamberg wbamberg merged commit 26f6807 into mdn:main Oct 12, 2023
@chrisdavidmills chrisdavidmills deleted the beforeunload-update branch October 13, 2023 07:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:WebAPI Web API docs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants