useMagicModal
Close the current stack entry from its own component and return typed data.
useMagicModal<T = void>(): {
hide(data: T): void;
}useMagicModal is the close API for a component rendered by magicModal.show. Its context binds
hide to the exact stack entry that rendered the component, so it does not need a modal ID.
Modal content only
Call this hook from a component rendered by magicModal.show. Outside that
provider, hide is a silent no-op; it cannot discover or close a global stack
entry.
Complete typed flow
import { Pressable, Text, View } from "react-native";
import { MagicModalHideReason, magicModal, useMagicModal } from "magic-modal";
type Confirmation = {
approved: boolean;
};
function ConfirmationModal() {
const { hide } = useMagicModal<Confirmation>();
return (
<View>
<Text accessibilityRole="header">Publish this release?</Text>
<Pressable
accessibilityRole="button"
onPress={() => hide({ approved: true })}
>
<Text>Publish</Text>
</Pressable>
<Pressable
accessibilityRole="button"
onPress={() => hide({ approved: false })}
>
<Text>Keep editing</Text>
</Pressable>
</View>
);
}
export async function requestPublishApproval() {
const result = await magicModal.show<Confirmation>(ConfirmationModal, {
accessibilityLabel: "Confirm release publication",
});
if (result.reason === MagicModalHideReason.INTENTIONAL_HIDE) {
return result.data.approved;
}
console.info("Publish confirmation dismissed:", result.reason);
return false;
}Pass the same return type to useMagicModal<T>() and show<T>(). TypeScript checks the value sent
to hide, while the reason check narrows the awaited result before data is read.
Backdrop press, swipe, Android Back, web Escape, and hideAll() resolve the promise with their own
reason and no data. Use try/catch for errors from the async work that follows the modal result.
Hook or imperative API
| Situation | API |
|---|---|
| The current modal closes itself | useMagicModal<T>().hide(data) |
| Application code opens a modal and waits for its result | await magicModal.show<T>(component) |
| Code outside the modal closes one known entry | magicModal.hide(data, { modalID }) |
| A logout or reset boundary clears the stack | magicModal.hideAll() |
For a modal that returns no data:
const { hide } = useMagicModal();
<Button title="Done" onPress={() => hide()} />;hide always creates an INTENTIONAL_HIDE result. Backdrop, back-button,
swipe, and global cleanup results are produced by their respective close
paths.
Read hide results for the complete result union and every dismissal reason.