Cue gives a React app one small, imperative overlay environment. Create it once, define overlays from that instance, and mount its provider near the root.
npm i @vlkoss/cueStart with no configuration:
// components/cue.ts
"use client";
import { createCue } from "@vlkoss/cue";
export const cue = createCue();Mount that instance once:
import { cue } from "./components/cue";
export function App() {
return (
<cue.OverlayProvider>
<Page />
</cue.OverlayProvider>
);
}Define an overlay from the same instance. The callback receives application props first and Cue runtime context second.
import { cue } from "./components/cue";
export const confirmDialog = cue.createOverlay<{ message: string }, boolean>((props, ctx) => (
<div role="dialog" aria-hidden={!ctx.open}>
<p>{props.message}</p>
<button type="button" onClick={() => ctx.close({ result: false })}>
Cancel
</button>
<button type="button" onClick={() => ctx.close({ result: true })}>
Confirm
</button>
</div>
));Open it from event handlers, effects, or other client-side code:
const close = confirmDialog.open({ message: "Archive this project?" });
const result = await confirmDialog.openAsync({ message: "Delete this project?" });
confirmDialog.closeAll();open() returns a close function for that instance. close({ result }) settles the matching openAsync() call. Props with only optional keys can be omitted from open() and openAsync().
If your app uses shadcn, the Using Cue with shadcn guide explains the registry setup and the shared backdrop adapter.
Cue has no backdrop or shared components by default. Add them with createCue({ backdrop, delay, components }) when your application needs them. See the Customization guide.
Put createCue() and the overlay definitions in a client-side module. A server layout can render the provider:
// app/layout.tsx
import { cue } from "@/components/cue";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<cue.OverlayProvider>{children}</cue.OverlayProvider>
</body>
</html>
);
}Docs design inspired by Emil Kowalski (@emilkowalski), especially Sonner and Vaul.