Fires handler once when the user attempts to navigate away (beforeunload). Useful for unsaved-changes warnings.
Usage
import { usePageLeave } from '@kivora/react';
function Editor({ hasUnsavedChanges }) {
usePageLeave(() => {
if (hasUnsavedChanges) {
console.log('User is leaving with unsaved changes');
}
});
return <textarea>{/* Editor */}</textarea>;
}
Parameters
Callback function fired when the user attempts to leave the page.
Examples
Unsaved changes warning
function FormEditor() {
const [content, setContent] = useState('');
const [saved, setSaved] = useState(true);
usePageLeave(() => {
if (!saved) {
// Note: Modern browsers ignore custom messages
// but still show a generic confirmation dialog
return 'You have unsaved changes!';
}
});
const handleChange = (e) => {
setContent(e.target.value);
setSaved(false);
};
return (
<>
<textarea value={content} onChange={handleChange} />
<button onClick={() => {
saveContent(content);
setSaved(true);
}}>
Save
</button>
</>
);
}
Analytics tracking
function Article() {
const [readTime, setReadTime] = useState(0);
useEffect(() => {
const start = Date.now();
return () => {
setReadTime(Date.now() - start);
};
}, []);
usePageLeave(() => {
analytics.track('article_exit', {
timeSpent: readTime,
scrollDepth: window.scrollY,
});
});
return <article>{/* Content */}</article>;
}
Auto-save on exit
function NoteEditor() {
const [note, setNote] = useState('');
usePageLeave(() => {
if (note.trim()) {
localStorage.setItem('draft', note);
}
});
return (
<textarea
value={note}
onChange={(e) => setNote(e.target.value)}
placeholder="Your notes..."
/>
);
}
Conditional warning
function CheckoutForm() {
const [step, setStep] = useState(1);
const totalSteps = 3;
usePageLeave(() => {
if (step > 1 && step < totalSteps) {
console.warn('User leaving incomplete checkout');
}
});
return <div>{/* Multi-step form */}</div>;
}
Session cleanup
function AuthenticatedApp() {
usePageLeave(() => {
// Clean up session data
sessionStorage.clear();
// Notify server
navigator.sendBeacon('/api/session/end',
JSON.stringify({ timestamp: Date.now() })
);
});
return <div>{/* App */}</div>;
}
Notes
- Uses the
beforeunload event
- Modern browsers ignore custom messages and show a generic confirmation dialog
- The handler cannot prevent navigation or show custom UI
- Use
navigator.sendBeacon() for reliable analytics tracking on page exit
- The handler is called when:
- User closes the tab/window
- User navigates to a different URL
- User refreshes the page
Type Definitions
function usePageLeave(handler: () => void): void;