Skip to content

r2hu1/unsave-provider

Repository files navigation

Unsave Provider

A React context provider for Next.js that handles unsaved changes with elegant toasts, drawers, and modals.

Preview

Features

  • Desktop Toast - Floating toast at bottom center with Save/Discard actions
  • Mobile Bottom Drawer - Slides up from bottom on small screens
  • Navigation Modal - Confirmation dialog for cross-page navigation
  • Browser Protection - Native beforeunload prompt on page refresh
  • Link Interception - Automatically handles next/link components
  • History API - Intercepts pushState for programmatic navigation

Installation

Manual

Copy the component to your project:

cp components/unsave-provider.tsx your-project/components/

Using shadcn/ui

npx shadcn@latest add https://raw.githubusercontent.com/gluer-space/unsave-provider/main/public/r/registry.json

Usage

1. Wrap Your App with Provider

// app/layout.tsx
import { UnsavedChangesProvider } from "@/components/unsave-provider";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <UnsavedChangesProvider>{children}</UnsavedChangesProvider>
      </body>
    </html>
  );
}

2. Use the Hook in Your Components

"use client";

import { useUnsavedChanges } from "@/components/unsave-provider";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";

export function EditableForm() {
  const [title, setTitle] = useState("");

  const { setDirty, isDirty } = useUnsavedChanges({
    onSave: async () => {
      await saveData({ title });
    },
    onCancel: () => {
      setTitle("");
    },
  });

  return (
    <form>
      <Input
        value={title}
        onChange={(e) => {
          setTitle(e.target.value);
          setDirty(true);
        }}
      />
      {isDirty && <p>You have unsaved changes</p>}
    </form>
  );
}

API Reference

useUnsavedChanges Hook

Props

Prop Type Description
onSave () => Promise<void> | void Callback when user clicks Save
onCancel () => void Optional cleanup callback on discard

Returns

Return Type Description
setDirty (dirty: boolean) => void Mark form as modified or clean
isDirty boolean Current dirty state

Behavior

Action Result
Edit form → Same page Shows toast (desktop) or drawer (mobile)
Edit form → Click link Shows confirmation modal
Edit form → router.push() Shows confirmation modal
Edit form → history.pushState() Shows confirmation modal
Edit form → Refresh/Close tab Browser's native prompt

Dependencies

  • React 18+
  • Next.js (App Router)
  • motion for animations
  • shadcn/ui components (Button, Dialog)

Getting Started

npm run dev

Open http://localhost:3000 to see the demo.

About

A React context provider for Next.js that handles unsaved changes with elegant toasts, drawers, and modals.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors