API
createCue, createOverlay, context, and the provider.
createCue(options?)
createCue() creates one isolated overlay environment. Its returned Cue instance is the only place to create overlays and the only provider that can render them.
const cue = createCue({
backdrop: OverlayBackdrop,
delay: 300,
components: {
wrapper: OverlayWrapper,
content: OverlayContent,
footer: OverlayFooter,
},
});components is an application-defined map. Cue does not reserve keys such as header or footer. The exact map is inferred in every overlay callback.
backdrop is the environment's shared backdrop. Cue renders it once for the stack. Individual overlays do not render it.
delay is the environment close delay in milliseconds. Default 300. close({ delay }) overrides it for one overlay instance.
The backdrop receives open and close. open stays true while any overlay instance that did not opt out is open, then false during the last instance's close delay. Call close with { strategy: "last" } to close the top open overlay instance or { strategy: "all" } to close every open overlay instance.
For the shadcn Dialog adapter, see Using Cue with shadcn. For custom backdrops and shared components, see Customization.
cue.OverlayProvider
<cue.OverlayProvider>{children}</cue.OverlayProvider>Mount it once, near the root. The provider portals the shared backdrop and every overlay instance to document.body. Pass container to portal somewhere else.
A second OverlayProvider for the same Cue environment renders children only and warns in development. Unmounting the outlet provider dismisses pending openAsync() calls as undefined and clears the stack.
An overlay instance remains mounted while its close delay runs. The shared backdrop stays mounted for that window when the instance is the last.
cue.createOverlay<Props, Result>(render, options?)
const dialog = cue.createOverlay<{ message: string }, boolean>((props, ctx) => {
const components = ctx.components;
return (
<components.wrapper open={ctx.open} onOpenChange={ctx.onOpenChange}>
<components.content>{props.message}</components.content>
</components.wrapper>
);
});The callback receives:
type OverlayContext<Components, Result> = {
open: boolean;
onOpenChange: (isOpen: boolean) => void;
close: (options?: { result?: Result; delay?: number }) => void;
components: Components;
};props contains only the object passed to open() or openAsync(). Do not expect open, close, or components there.
Pass { backdrop } as the second argument to replace the environment dim, or { backdrop: false } to opt out of providing one so a lower overlay instance can keep it:
const popover = cue.createOverlay(() => <Popover />, { backdrop: false });open() and openAsync() still take application props only.
Handle methods
| Method | Description |
|---|---|
open(props?) | Opens one instance and returns that instance's close function. The function accepts the same { result, delay } as ctx.close. Props are required when Props has a required key. |
openAsync(props?) | Opens one instance and returns Promise<Result | undefined>. Dismissal resolves undefined. |
closeAll(options?) | Closes every live instance from this overlay definition. A result settles every pending openAsync() from that definition. |
Closed instances always unmount after delay. There is no unmount: false option.
Optional props
An overlay with no props or only optional props accepts a bare call:
const settings = cue.createOverlay(() => <Dialog />);
settings.open();
const notice = cue.createOverlay<{ title?: string }>(() => <Dialog />);
notice.open();
notice.open({ title: "Hello" });Required props remain required:
const confirm = cue.createOverlay<{ message: string }>(() => <Dialog />);
confirm.open({ message: "Continue?" });
// confirm.open(); // TypeScript errorShared backdrop behavior
Cue renders no dim when every open overlay instance opted out, one dim for one overlay instance, and still one dim for a stack. Closing the top overlay instance leaves the dim while a lower instance remains. Closing the last instance sets open={false} on the dim and removes it when that instance's close delay ends. closeAll() follows the same rule.
The dim comes from the top open overlay instance that did not opt out: that overlay definition's replacement, otherwise the environment's.