Open the parent boundary to begin.
"use client";
import { Button, Stack, Text, useCanDismiss } from "@vortexlabs/vortex";
import React from "react";
export const UseCanDismissOrderingExample = () => {
const [parentOpen, setParentOpen] = React.useState(false);
const [childOpen, setChildOpen] = React.useState(false);
const [message, setMessage] = React.useState("Open the parent boundary to begin.");
const parentRef = React.useRef<HTMLDivElement>(null);
const childRef = React.useRef<HTMLDivElement>(null);
const canDismissParent = useCanDismiss({
active: parentOpen,
contentRef: parentRef,
hasTrigger: false,
});
const canDismissChild = useCanDismiss({
active: childOpen,
contentRef: childRef,
hasTrigger: false,
});
const dismissParent = () => {
if (canDismissParent()) {
setParentOpen(false);
setMessage("Parent dismissed.");
} else setMessage("Dismiss the child boundary first.");
};
return (
<Stack gap={3} width="100%">
<Button
variant="secondary"
onClick={() => {
setParentOpen(true);
setMessage("Parent boundary opened.");
}}
>
Open parent boundary
</Button>
{parentOpen && (
<Stack
gap={3}
padding={4}
backgroundColor="surface-subtlest"
borderRadius="md"
attributes={{ ref: parentRef }}
>
<Text weight="medium">Parent boundary</Text>
<Stack direction="row" gap={3} wrap>
<Button size="sm" onClick={() => setChildOpen(true)}>
Open child boundary
</Button>
<Button size="sm" variant="secondary" onClick={dismissParent}>
Request parent dismissal
</Button>
</Stack>
{childOpen && (
<Stack
gap={3}
padding={4}
borderColor="default"
borderRadius="md"
attributes={{ ref: childRef }}
>
<Text>Child boundary</Text>
<Button
size="sm"
variant="secondary"
onClick={() => {
if (canDismissChild()) {
setChildOpen(false);
setMessage("Child dismissed. The parent can now close.");
}
}}
>
Dismiss child boundary
</Button>
</Stack>
)}
</Stack>
)}
<Text attributes={{ role: "status" }}>{message}</Text>
</Stack>
);
};Features
- Registers an active dismissal boundary.
- Checks whether a newer overlay should handle dismissal first.
- Supports trigger-based nesting or explicit ordering without a trigger.
Call canDismiss() inside your dismissal handler. It checks ordering; your code closes the overlay. Pass active so closed overlays stop participating.
Trigger Nesting
Pass triggerRef to detect overlays opened inside another overlay. Use hasTrigger: false for ordering without trigger nesting.
const canDismiss = useCanDismiss({
active: open,
contentRef,
triggerRef,
});Nonmodal Overlays
Set modal: false so this overlay does not block another overlay’s dismissal. A newer modal overlay can still block it.
const canDismiss = useCanDismiss({
active: open,
contentRef,
hasTrigger: false,
modal: false,
});Inactive instances return true; guard dismissal handlers with your open state. Registrations are removed on cleanup.
Use Drawer for a complete overlay. This hook does not render UI, trap focus, or lock scrolling.