What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

You cannot choose the wording in a browser’s leave-site warning. Use the beforeunload event to request a browser-managed confirmation when a page has unsaved changes. Modern browsers replace your message with their own generic text, may suppress the dialog until the user interacts with the page, and do not guarantee that the event runs on every way a document can disappear.

What the leave-site alert is

A leave-site alert is the confirmation a browser may display when a document is about to unload because the user is closing a tab, reloading, navigating to another URL, or otherwise leaving the page. Its legitimate purpose is protecting work that exists only in the current page, such as unsaved form edits.

JavaScript can request that confirmation by canceling the beforeunload event. JavaScript cannot supply the sentence shown in the dialog. As MDN puts it: “Only show a generic browser-specified string in the displayed dialog. This cannot be controlled by the webpage code.” The exact wording, punctuation, and language therefore vary by browser, operating system, and user settings.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable implementation pattern

Track whether the user has made changes that are not saved. Register one handler while that state is true, then remove it immediately after saving or discarding the changes.

const beforeUnloadHandler = (event) => {
  event.preventDefault();
  // Legacy support for browsers that still rely on returnValue.
  event.returnValue = true;
};

function setHasUnsavedChanges(hasUnsavedChanges) {
  if (hasUnsavedChanges) {
    window.addEventListener("beforeunload", beforeUnloadHandler);
  } else {
    window.removeEventListener("beforeunload", beforeUnloadHandler);
  }
}

const form = document.querySelector("#profile-form");

form.addEventListener("input", () => {
  setHasUnsavedChanges(true);
});

form.addEventListener("submit", () => {
  // If the save succeeds asynchronously, call this in the success path.
  setHasUnsavedChanges(false);
});

Call setHasUnsavedChanges(true) only after an edit makes the page meaningfully different from its saved state. Call it with false after a successful save, after a deliberate reset, or after restoring the original values. Removing the listener matters: an always-on handler can warn users who have nothing to lose and prevents Firefox from placing the page in its back/forward cache.

Why both lines are present

event.preventDefault() is the current way to request the confirmation. Setting event.returnValue = true keeps compatibility with implementations that still look for the legacy property. With addEventListener(), returning a truthy value from the callback does not request the dialog; that behavior applies to an onbeforeunload property handler.

Do not attach a new anonymous function for every edit

removeEventListener() needs the same function object that was registered. Keep the handler in a variable, as in the example, rather than creating a fresh arrow function on every call. If your application has several forms, centralize the dirty-state decision so one listener is added and removed predictably.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why your custom message does not appear

Older examples often assign a string such as event.returnValue = "You have unsaved changes". Current browsers do not display that string. They show a generic, browser-controlled prompt instead. Code that tests for an exact phrase is consequently brittle and should be removed.

The same restriction applies if you try to call window.confirm() from the beforeunload handler. The exit prompt is a restricted browser operation; it is not a normal JavaScript modal that accepts arbitrary copy.

Conditions that affect whether the warning appears

User activation is normally required

Modern implementations require “sticky” user activation before showing a beforeunload dialog. A page that opens in a background tab, receives no click, key press, or comparable interaction, and then attempts to unload may produce no prompt. Design the feature around protecting an interacted-with editing session, not around forcing a dialog for every visit.

The event is not a save mechanism

beforeunload is a last-chance warning, not a reliable place to write data. A mobile example documented by MDN is: the user switches to another app, later closes the browser from the app manager, and the page never receives the event. Crashes, power loss, process termination, navigation in another context, and browser policies can likewise bypass it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Save drafts during editing when practical. Use server-side autosave, local storage or IndexedDB, and an explicit recovery flow appropriate to the sensitivity of the data. Treat the leave-site prompt as an additional guard against an accidental navigation, never as the only copy of the user’s work.

Back/forward cache trade-off

Firefox does not place pages with beforeunload listeners in its back/forward cache. A listener that remains attached for the entire lifetime of a page can therefore make history navigation slower. Conditional registration limits that cost and accurately communicates when a warning is needed.

Use confirm() for actions your application controls

window.confirm(message) is a separate mechanism. It accepts optional text supplied by your code and returns true when the user accepts or false when the user cancels.

const deleteButton = document.querySelector("#delete-record");

deleteButton.addEventListener("click", async (event) => {
  const accepted = window.confirm(
    "Delete this record? This action cannot be undone."
  );

  if (!accepted) {
    event.preventDefault();
    return;
  }

  await deleteRecord();
});

This is appropriate for deleting a record, submitting an irreversible change, or following a link your code controls. It is not a way to customize the browser’s tab-close or cross-origin navigation prompt. Browsers can suppress or bypass in-page dialogs in some conditions, and excessive modal prompts harm usability. For complex or accessible workflows, use an application-managed dialog with keyboard focus handling, an explicit cancel action, and text that explains the consequence.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choosing the right protection for common cases

Situation Mechanism Can your code set the text? Main limitation
User edits would be lost by closing, reloading, or leaving beforeunload No; the browser supplies generic wording May require user activation and may not fire on every lifecycle path
User clicks Delete, Publish, or another irreversible control window.confirm() or a custom dialog Yes Dialogs may be suppressed; modal UX must be accessible
Long-running form or editor needs recovery Autosave plus draft restoration Yes, in your own UI Requires storage, conflict handling, and a recovery design

Testing checklist

  • Load the page and leave without editing: no warning should be requested.
  • Edit a field, then reload or follow a navigation: a browser-controlled warning may appear after the page has received user interaction.
  • Save successfully, then leave: remove the listener before navigation so no stale warning appears.
  • Cancel the browser prompt and verify the document remains usable and the edited values are intact.
  • Test a normal link, address-bar navigation, reload, tab close, history navigation, mobile app switching, and a browser restart scenario. These paths do not all provide the same lifecycle guarantees.
  • Test with keyboard-only input and with assistive technology; do not make the warning the only explanation of what will happen.

Troubleshooting

No dialog appears after adding the listener

  • Confirm that the handler calls event.preventDefault() and sets event.returnValue = true.
  • Make sure the listener is attached to window, and that the code path actually marks the document dirty.
  • Interact with the page first. Modern browsers may suppress the prompt without sticky user activation.
  • Check that your test action really unloads the document. An in-page route change in a single-page application may never trigger beforeunload.
  • Do not expect a custom string; the browser may show a short generic message or suppress the prompt under its policies.

The warning appears after saving

Remove the exact handler after the save has completed successfully, not merely when a save request starts. If the request fails, retain the dirty state and tell the user that the data is still unsaved. Avoid registering duplicate listeners each time a field changes.

The warning appears when nothing changed

Compare the current model with the last saved model instead of treating every input event as dirty forever. Clear the state after reset, undo back to the saved values, successful submission, or draft restoration that has been committed.

Back navigation feels slower in Firefox

Check whether a persistent beforeunload listener is blocking the back/forward cache. Register it only during the unsaved interval and remove it as soon as the page is clean.

Performance, reliability, and data-loss guidance

The event handler itself should be tiny: set the cancellation signals and return. Do not perform network requests, expensive serialization, or long computations there. Those operations may be terminated before completion. Perform saves before the user reaches the exit decision, and expose the save status in the page so the browser prompt is a backup rather than a surprise.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Because browser behavior differs and mobile termination can bypass the event, document the guarantee precisely in product requirements: “warns on supported document-exit paths when unsaved changes exist,” not “prevents all data loss.”

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup:

If what you actually need is a rendered image or PDF of a page for documentation, testing, or an AI workflow, ScreenshotNeo provides a single HTTP request instead of a browser automation setup. It is a website screenshot API and MCP server for developers.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for parameters and response details. Before capture, it can accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and whether the shot was billed. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free. Every feature is available on every plan. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

FAQ

Can JavaScript read the exact leave-site text shown by the browser?

No. The dialog copy is browser-controlled, and your page should not depend on a particular phrase.

Does beforeunload run when a user closes a mobile browser from the app switcher?

Not reliably. A documented mobile sequence can terminate the page without firing the event, so draft persistence is still necessary.

Can I warn before an internal single-page-app route change?

Not with beforeunload alone. Intercept the route action in your application and present a page-controlled confirmation or custom dialog.

Should I leave the listener installed permanently?

No. Attach it only while unsaved changes exist and remove it after the data is saved or cleared.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can JavaScript read the exact leave-site text shown by the browser?

No. The dialog copy is browser-controlled, and your page should not depend on a particular phrase.

Does beforeunload run when a user closes a mobile browser from the app switcher?

Not reliably. A documented mobile sequence can terminate the page without firing the event, so draft persistence is still necessary.

Can I warn before an internal single-page-app route change?

Not with beforeunload alone. Intercept the route action in your application and present a page-controlled confirmation or custom dialog.

Should I leave the listener installed permanently?

No. Attach it only while unsaved changes exist and remove it after the data is saved or cleared.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.