Dismissal
Dismissal is configurable per view: gestures, outside press, and Escape can each be allowed, prevented, or decided at runtime.
Dismissal has three independent inputs: travel, outside interaction, and Escape. Treat them as product policy rather than assuming every overlay should close from every input.
Policy matrix
| Input | Control |
|---|---|
| swipe or programmatic close destination | dismissible |
| outside pointer interaction | onClickOutside |
| Escape | onEscapeKeyDown |
| enabled travel directions | tracks |
| native rubber-band beyond the end | swipeOvershoot |
Static and conditional policy
<Sheet.View
dismissible
onClickOutside={{ dismiss: false }}
onEscapeKeyDown={({ changeDefault, nativeEvent }) => {
if (formState.isDirty) {
changeDefault({ dismiss: false });
announce("Save or discard your changes first");
}
}}
/>changeDefault changes Velvet's default for that interaction. It does not cancel unrelated application handlers.
Alert dialogs
Use sheetRole="alertdialog" only for an urgent decision. Swipe dismissal is disabled by default and the workflow should present explicit safe and destructive actions.
Nested dismissal
Only the frontmost modal responds to Escape or outside interaction. Closing it restores focus to its opener inside the previous layer; closing the last layer restores focus to the page trigger.