A lightweight React solution for managing multiple popups without chaos. Prevents popup race conditions by automatically queuing and showing popups one at a time, sorted by priority.
- ๐ซ No More Popup Chaos: Only one popup shows at a time
- ๐ฏ Priority-Based Queuing: Higher priority popups show first
- ๐จ Complete Design Freedom: Each popup is a self-contained React component
- ๐ Non-Escapable Modals: Critical popups that require user action
- โฐ Frequency Control: Prevent spam with "once", "session", or "always" rules
- ๐พ Smart State Tracking: Respects user dismissals and prevents repeated annoyance
- โก Simple API: Easy integration with minimal configuration
# Install dependencies
npm install
# Start development server
npm run devimport { usePopupQueue } from "./hooks/usePopupQueue";
function App() {
const { addPopup } = usePopupQueue();
const showWelcome = () => {
addPopup({
id: "welcome",
content: <MyWelcomeComponent />,
priority: 5,
});
};
return <button onClick={showWelcome}>Show Popup</button>;
}import { usePopupActions } from "./hooks/usePopupActions";
function MyWelcomeComponent() {
const { close } = usePopupActions();
return (
<div className="bg-white rounded-lg shadow-xl max-w-md p-6">
<h2 className="text-xl font-bold mb-4">Welcome!</h2>
<p className="mb-4">Thanks for joining us.</p>
<button
onClick={close}
className="bg-blue-600 text-white px-4 py-2 rounded"
>
Get Started
</button>
</div>
);
}// Critical popup that cannot be dismissed with ESC or backdrop click
addPopup({
id: "terms-update",
content: <TermsAcceptance />,
priority: 10,
escapable: false, // Must complete action to continue
});Control how often popups can be shown to prevent spam:
// Show only once (default behavior)
addPopup({
id: "welcome",
content: <Welcome />,
frequency: "once", // Won't show again after dismissal
});
// Show once per browser session
addPopup({
id: "session-tip",
content: <QuickTip />,
frequency: "session", // Shows again after page refresh
});
// Always show (ignore dismissal)
addPopup({
id: "critical-alert",
content: <SecurityAlert />,
frequency: "always", // Shows every time (use sparingly)
});const {
// State
queue, // Array of queued popups
currentPopup, // Currently displayed popup
queueLength, // Number of popups in queue
// Actions
addPopup, // Add popup to queue
showNextPopup, // Manually show next popup
clearQueue, // Clear all queued popups
resetAllStates, // Reset all popup states for testing
// Status
isQueueEmpty, // Boolean: is queue empty?
hasCurrentPopup, // Boolean: is popup currently showing?
} = usePopupQueue();// Use inside popup components
const {
close, // Close current popup and show next
closeAll, // Close current popup and clear queue
showNext, // Show next popup (for multi-step flows)
} = usePopupActions();interface PopupConfig {
id: string; // Unique identifier
content: ReactNode; // Your custom React component
priority?: number; // Higher = more important (default: 5)
type?: string; // Optional categorization
frequency?: PopupFrequency; // Show frequency rules (default: "once")
escapable?: boolean; // Can be closed with ESC/backdrop (default: true)
expiresAt?: Date; // Auto-expire date
}
type PopupFrequency = "once" | "session" | "always";| Frequency | Behavior | Use Case |
|---|---|---|
"once" |
Shows once, never again after dismissal | Welcome messages, terms updates |
"session" |
Shows once per browser session | Session tips, temporary notifications |
"always" |
Shows every time, ignores dismissal | Critical alerts, testing |
- No Templates: Each popup defines its own complete layout
- Modal Only: All popups are modal dialogs (no banners, toasts, etc.)
- Self-Contained: Popup components handle their own styling and actions
- Minimal State: Essential state tracking without complexity
Popups are automatically sorted by priority (highest first):
- 10: Critical system alerts
- 8-9: Important warnings
- 5-7: General notifications
- 2-4: Promotions and optional content
- 1: Low priority background items
- Dismissal Tracking: Dismissed popups won't show again (respects frequency)
- Session Storage: Persisted across browser sessions
- Reset Capability: Clear all states for testing/demos
The included demo showcases:
- Main Demo: Adds 5 different popups by priority
- Individual Controls: Payment (once), Tour (once), Rating (session), Upgrade (always)
- Non-Escapable Modal: Critical popup that requires action
- Frequency Testing: Different frequency behaviors you can test interactively
- Queue Visualization: Real-time queue status
- Reset Functions: Clear states for repeated testing
- "Once" Frequency: Payment/Tour buttons - dismiss once, won't show again
- "Session" Frequency: Rating button - shows again after page refresh
- "Always" Frequency: Upgrade button - shows every time, even after dismissal
- React 19 with TypeScript
- Vite for development
- Tailwind CSS for styling
- Zustand for state management
- ShadCN UI for components
Each popup is a complete React component with its own styling:
function PaymentForm() {
const { close } = usePopupActions();
return (
<div className="bg-white rounded-lg shadow-xl max-w-md p-6">
{/* Your complete popup design here */}
<button onClick={close}>Done</button>
</div>
);
}// Add multiple popups - they'll show one at a time by priority
addPopup({ id: "terms", content: <Terms />, priority: 9 });
addPopup({ id: "payment", content: <Payment />, priority: 8 });
addPopup({ id: "welcome", content: <Welcome />, priority: 5 });
// Shows: Terms โ Payment โ WelcomeaddPopup({
id: "critical-update",
content: <SecurityAlert />,
priority: 10,
escapable: false, // User must complete the action
});// Welcome message - show once per user, ever
addPopup({
id: "welcome",
content: <Welcome />,
frequency: "once", // Default: won't show again after dismissal
});
// Quick tip - show once per session
addPopup({
id: "productivity-tip",
content: <ProductivityTip />,
frequency: "session", // Shows again after browser restart
});
// Critical system alert - always show
addPopup({
id: "system-maintenance",
content: <MaintenanceAlert />,
frequency: "always", // Ignores dismissal, shows every time
priority: 10,
});- Login Flows: Queue multiple popups without overwhelming users
- Onboarding: Sequential user guidance
- Critical Alerts: Non-dismissible security warnings
- Terms Updates: Mandatory acceptance flows
- Payment Issues: Important account notifications
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
MIT License - feel free to use in your projects!
Simple, focused popup management for better user experiences โจ