Reoverlay
April 25, 2026 ยท View on GitHub
A tiny, typed modal manager for React. Reoverlay gives you one top-level
ModalContainer and a small imperative API for opening, stacking, and closing
modals from anywhere in your app.
Install
pnpm add reoverlay
npm install reoverlay
yarn add reoverlay
Quick Start
Mount ModalContainer once near the root of your app.
import { ModalContainer } from 'reoverlay'
export function App() {
return (
<>
<Routes />
<ModalContainer />
</>
)
}
Create a modal. ModalWrapper is optional, but it provides the default backdrop,
animations, outside-click close behavior, and Escape close behavior.
import { ModalWrapper, Reoverlay } from 'reoverlay'
import 'reoverlay/ModalWrapper.css'
type ConfirmModalProps = {
message: string
onConfirm: () => void
}
export function ConfirmModal({ message, onConfirm }: ConfirmModalProps) {
return (
<ModalWrapper aria-label="Confirm action">
<p>{message}</p>
<button onClick={onConfirm} type="button">
Confirm
</button>
<button onClick={() => Reoverlay.hideModal()} type="button">
Cancel
</button>
</ModalWrapper>
)
}
Open the modal directly.
import { Reoverlay } from 'reoverlay'
import { ConfirmModal } from './ConfirmModal'
Reoverlay.showModal(ConfirmModal, {
message: 'Delete this post?',
onConfirm: () => {
Reoverlay.hideModal()
},
})
Named Modals
You can configure modal names once and open them later by string. This is useful for app-wide modals, interceptors, and places where importing the modal component would be awkward.
import { ModalContainer, Reoverlay } from 'reoverlay'
import { AuthModal, ConfirmModal } from './modals'
Reoverlay.config([
{ name: 'AuthModal', component: AuthModal },
{ name: 'ConfirmModal', component: ConfirmModal },
])
export function App() {
return (
<>
<Routes />
<ModalContainer />
</>
)
}
Reoverlay.showModal('ConfirmModal', {
message: 'Archive this item?',
})
API
Reoverlay.config(configData)
Registers named modals.
type ModalConfigItem = {
name: string
component: React.ElementType | React.ReactElement
}
Names must be unique within a single config call.
Reoverlay.showModal(modal, props?)
Shows a modal. modal can be a configured string name, a React component, or a
React element. props are passed to the modal when it renders.
Reoverlay.showModal(MyModal, { title: 'Hello' })
Reoverlay.showModal(<MyModal title="Hello" />)
Reoverlay.showModal('MyModal', { title: 'Hello' })
Reoverlay.hideModal(modalName?)
Hides a modal. When no name is provided, the last visible modal is hidden. When a name is provided, that configured modal is hidden.
Reoverlay.hideModal()
Reoverlay.hideModal('ConfirmModal')
Reoverlay.hideAll()
Closes every active modal.
Reoverlay.hideAll()
ModalWrapper
ModalWrapper is a small default shell. You can skip it and render your own
modal UI if you only want Reoverlay's state orchestration.
import type { ModalWrapperProps } from 'reoverlay'
| Prop | Type | Default |
|---|---|---|
animation | 'fade' | 'zoom' | 'flip' | 'door' | 'rotate' | 'slideUp' | 'slideDown' | 'slideLeft' | 'slideRight' | 'fade' |
wrapperClassName | string | '' |
contentContainerClassName | string | '' |
onClose | (event) => void | () => Reoverlay.hideModal() |
closeOnEscape | boolean | true |
aria-label | string | undefined |
aria-labelledby | string | undefined |
aria-describedby | string | undefined |
role | 'dialog' | 'alertdialog' | 'dialog' |
The preferred CSS import is:
import 'reoverlay/ModalWrapper.css'
The legacy import path is still supported:
import 'reoverlay/lib/ModalWrapper.css'
Development
This repo uses pnpm workspaces.
pnpm install
pnpm dev
Useful scripts:
pnpm lint
pnpm typecheck
pnpm test
pnpm build:package
pnpm build:demo
pnpm build:all
The demo lives in demo/ and builds with Vite for GitHub Pages under
/reoverlay/.
Release Checklist
- Update the version in
package.json. - Run
pnpm install --frozen-lockfile. - Run
pnpm lint,pnpm typecheck,pnpm test, andpnpm build:all. - Inspect the package contents with
npm pack --dry-run. - Publish with
pnpm publish --otp <code>if your npm account requires 2FA. - Deploy the demo with
pnpm --filter reoverlay-demo deploy.