The ModalStore is a simple global state manager that tracks whether any modal is currently open in the application. This is useful for adjusting UI elements (like toast notifications or floating buttons) when modals are displayed.
Import
import { useModalStore } from "../stores/ModalStore"
Usage
const Login = () => {
const setModalOpen = useModalStore(state => state.setModalOpen)
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false)
const openModal = () => {
setIsLoginModalOpen(true)
setModalOpen(true) // Notify global state
}
const closeModal = () => {
setIsLoginModalOpen(false)
setModalOpen(false) // Notify global state
}
return (
<>
<button onClick={openModal}>Sign in</button>
<Modal isOpen={isLoginModalOpen} closeModal={closeModal}>
{/* Modal content */}
</Modal>
</>
)
}
const AddBookmark = () => {
const isAnyModalOpen = useModalStore(state => state.isAnyModalOpen)
return (
<div
className={`fixed transition-all ${
isAnyModalOpen ? "-bottom-20" : "bottom-4"
}`}
>
{/* Floating input that moves down when modal is open */}
</div>
)
}
const App = () => {
const isAnyModalOpen = useModalStore(state => state.isAnyModalOpen)
return (
<main>
<Toaster
position="bottom-center"
offset={{
bottom: isAnyModalOpen ? "16px" : "102px"
}}
/>
</main>
)
}
State Properties
Indicates whether any modal is currently open in the application. Use this to adjust positioning of floating elements, toast notifications, or other UI components that should respond to modal state.
Methods
setModalOpen
Sets the global modal state.
Set to true when opening a modal, false when closing it.
const setModalOpen = useModalStore(state => state.setModalOpen)
// When opening a modal
setModalOpen(true)
// When closing a modal
setModalOpen(false)
Type Definitions
type ModalState = {
isAnyModalOpen: boolean
setModalOpen: (isOpen: boolean) => void
}
Implementation Details
- State Management: Uses Zustand for lightweight global state
- Single Source of Truth: Tracks whether ANY modal is open, not specific modals
- No Modal Logic: This store only tracks state; actual modal rendering and logic should be handled by individual components
- UI Coordination: Primarily used to coordinate UI elements that need to adjust when modals are present
Common Patterns
Modal Component Integration
const CustomModal = ({ isOpen, onClose, children }) => {
const setModalOpen = useModalStore(state => state.setModalOpen)
useEffect(() => {
setModalOpen(isOpen)
}, [isOpen, setModalOpen])
const handleClose = () => {
setModalOpen(false)
onClose()
}
return (
<Dialog open={isOpen} onClose={handleClose}>
{children}
</Dialog>
)
}
Responsive UI Elements
const FloatingButton = () => {
const isAnyModalOpen = useModalStore(state => state.isAnyModalOpen)
return (
<button
className={`fixed bottom-4 right-4 transition-transform ${
isAnyModalOpen ? 'translate-y-20' : 'translate-y-0'
}`}
>
Add
</button>
)
}
Toast Offset Adjustment
// Adjust toast position based on whether modals are open
const isAnyModalOpen = useModalStore(state => state.isAnyModalOpen)
<Toaster
position="bottom-center"
offset={{
bottom: isAnyModalOpen ? "16px" : "102px"
}}
mobileOffset={{
bottom: isAnyModalOpen ? "16px" : "102px"
}}
/>
Best Practices
-
Always update global state: When opening or closing any modal, always call
setModalOpen() to keep global state in sync
-
Cleanup on unmount: If a modal component unmounts while open, ensure
setModalOpen(false) is called
-
Use for coordination only: This store should only be used to coordinate UI elements, not to manage individual modal states
-
Pair with local state: Each modal should maintain its own local open/close state and sync with the global store
const [isModalOpen, setIsModalOpen] = useState(false)
const setGlobalModalOpen = useModalStore(state => state.setModalOpen)
const openModal = () => {
setIsModalOpen(true)
setGlobalModalOpen(true)
}
const closeModal = () => {
setIsModalOpen(false)
setGlobalModalOpen(false)
}