Customization
Configure a custom backdrop and reusable components for a Cue environment.
createCue() needs no options. Add a backdrop, a close delay, or shared components when your overlays need them.
Custom backdrops
Pass a component through backdrop. It is not a dialog. Cue portals it with the overlay instances.
import { createCue, type CueBackdrop } from "@vlkoss/cue";
const OverlayBackdrop: CueBackdrop = ({ open, close }) => (
<div
aria-hidden="true"
data-open={open ? "" : undefined}
className="fixed inset-0 bg-black/50"
style={{ pointerEvents: open ? "auto" : "none" }}
onClick={() => close({ strategy: "last" })}
/>
);
export const cue = createCue({
backdrop: OverlayBackdrop,
delay: 300,
});open is true while the stack should show a dim, then false during the last overlay instance's close delay so the dim can fade out. Use { strategy: "last" } to close the top open overlay instance or { strategy: "all" } to close every open overlay instance.
An overlay definition can replace that dim, or opt out so a lower overlay instance keeps it:
const popover = cue.createOverlay(() => <Popover />, { backdrop: false });Opened alone, that overlay instance has no dim. Opened over a dialog that uses the environment backdrop, the dialog's dim stays.
This matters when overlays stack. Rendering a backdrop inside each dialog creates one element per dialog and makes the stack darker as it grows. A provider-level backdrop keeps the stack predictable.
Reusable components
The components option accepts any application-defined map:
export const cue = createCue({
components: {
wrapper: OverlayWrapper,
footer: OverlayFooter,
closeButton: OverlayCloseButton,
},
});Cue does not decide what those keys mean or render them for you. Each overlay chooses its own composition:
const dialog = cue.createOverlay<{ message: string }>((props, ctx) => {
const components = ctx.components;
return (
<components.wrapper>
<p>{props.message}</p>
<components.footer>
<components.closeButton onClick={() => ctx.close()} />
</components.footer>
</components.wrapper>
);
});The component keys and their types come from the createCue() call. A different Cue instance can use a different map without a global registry or module augmentation.
Isolated environments
Each Cue owns its own definitions, instances, provider, components, backdrop, and lifecycle state:
const appCue = createCue();
const adminCue = createCue();Opening an overlay from appCue has no effect on adminCue. Use separate instances when different parts of an application need independent overlay stacks.