RatingModalRate the app
How would you rate the app from zero to five?
Scores 0 through 3 open feedback. Scores 4 and 5 open the store prompt.latestA modal stack for React Native
Mount one MagicModalPortal at the app root. Call show() from any async flow and await the typed result.
rating-flow.tsx01const rating = await magicModal
.show<RatingAnswer>(RatingModal).promise;02await magicModal.show(
rating.data.score < 4
? FeedbackModal : StoreReviewModal
).promise;03await magicModal
.show(ThanksModal).promise;04return rating;RatingModalHow would you rate the app from zero to five?
Scores 0 through 3 open feedback. Scores 4 and 5 open the store prompt.The first Magic Modal flow asked for an app rating after a like. It could start from several screens and branch to feedback or the store. Both paths ended with a thank-you.
Every screen that can start the flow repeats the modal tree and its cleanup.
The flow lives outside the screens. Each caller awaits the same sequence.
The portal stays empty until show() runs.
Concurrent prompts keep their own place in the stack.
startRatingFlow()The shared flow owns the modal components and visibility state.
Start the rating flow and stack a notification over it. Close the top entry and the first promise is still waiting underneath.
Start the rating flow in the phone frame, or run update() in the web panel. This page mounts one MagicModalPortal for both.
rating-flow.tsconst result = await magicModal
.show(RatingPrompt)
.promiseThe stack is empty.Modal content mounts after show() runs.
No calls yet.Resolved values appear here.
Each action resolves or updates the current modal. The result decides what opens next.
delete-post.tsxconst result = await magicModal
.show<Confirmation>(() => (
<DeletePostModal />
))
.promise;
if (
result.reason === INTENTIONAL_HIDE &&
result.data.confirmed
) {
await deletePost(postID);
}This action cannot be undone.
Promise pendingModal calls can come from anywhere in the app. Each show() gets an ID and promise, so one flow cannot overwrite the modal that was already open.
post.tsxcomment.tsxproduct.tsxnotifications.tsrating(); branch(); thanks();magicModal.show() returnsAwait the close result, target this stack entry by ID, or replace its component while the same promise stays pending.
{
promise: Promise<HideReturn<T>>;
modalID: string;
update: (next: React.FC) => void;
}AVAILABLE IMMEDIATELYpromise01modalID02update03UPDATE REMOUNTSupdate() starts a fresh component mount. Local React state resets.
HideReturn<T> recordsA submitted answer, backdrop tap, swipe, Android back press, and hideAll() resolve differently. Only hide(data) returns a payload.
Answer here, swipe down, or choose another close action.
promise pendingconst result = await handle.promise;
// waiting for a closePress one action to resolve the promiseThe setup guide mounts the app-root portal and shows how to await a typed HideReturn<T>.