
Security News
AGENTS.md Gains Traction as an Open Format for AI Coding Agents
AGENTS.md is a fast-growing open format giving AI coding agents a shared, predictable way to understand project setup, style, and workflows.
@prezly/react-promise-modal
Advanced tools
The proper (and easy) way of doing modals in React. With Promises.
usePromiseModal()
is a React hook that allows you to define a modal
by providing a custom rendering function.
After defining your modal you can invoke it imperatively and await the returned promise to resolve, to get the modal resolution result.
usePromiseModal()
invoke()
await
// 1) Define your modal
const confirmation = usePromiseModal((props) => <MyModal {...props} />);
// 2) Call it in your event handler
async function handleClick() {
// 3) Wait for the modal to resolve
if (await confirmation.invoke()) {
// TODO: Perform the operation.
}
}
Demo: https://codesandbox.io/p/sandbox/romantic-lovelace-4pmm3k
The usePromiseModal()
hook` returns the following values:
const { invoke, modal, isDisplayed } = usePromiseModal(/* ... */);
invoke
— imperatively invoke the modal, optionally passing additional call-time arguments.
Returns a promise you can await to get the modal resolution value, when it's available.
Or undefined if the modal has been dismissed or cancelled.
modal
— the rendered modal markup (ReactElement | null
). You should always render this
value into your component subtree.
isDisplayed
— a boolean flag indicating if there is currently a pending modal
for this definition.
The modal render function receives these properties:
usePromiseModal(({ show, onDismiss, onSubmit }) => (
<MyModal show={show} onDismiss={onDismiss} onSubmit={onSubmit} />
));
show
— boolean to tell if the window is visible or not.
Used for in/out transitions.
Primarily intended to be used as react-bootstrap Modal show
property.
onDismiss
— should be invoked when the modal is dismissed.
Always resolves the promise to undefined
.
onSubmit
— should be invoked when the modal is submitted/confirmed.
Resolves to the value provided as an argument to it.
The resolve value cannot be undefined
, because it is already reserved for dismissal.
The function returns a Promise that is resolved with the submitted value,
or undefined
if it has been dismissed.
You can easily implement a confirmation modal using usePromiseModal()
:
import { usePromiseModal } from '@prezly/react-promise-modal';
function MyApp() {
const confirmation = usePromiseModal(({ show, onSubmit, onDismiss }) => {
// Use any modal implementation you want
<MyConfirmationModal title="⚠️ Are you sure?" show={show} onConfirm={() => onSubmit(true)} onDismiss={onDismiss} />
});
async function handleDeleteAccount() {
if (await confirmation.invoke()) {
console.log('Conirmed');
} else {
console.log('Cancelled');
}
}
return (
<div>
<button onClick={handleDeleteAccount}>Delete account</button>
{confirmation.modal}
</div>
)
}
Alert is basically the same as confirmation, except there is no difference whether
it is submitted or dismissed -- the modal has single action anyway.
So we only need onDismiss
:
import { usePromiseModal } from '@prezly/react-promise-modal';
function MyApp() {
const alert = usePromiseModal(({ show, onDismiss }) => {
// Use any modal implementation you want
<MyAlertModal title="✔ Account deleted!" show={show} onDismiss={onDismiss} />
});
async function handleDeleteAccount() {
await api.deleteAccount();
await alert.invoke();
}
return (
<div>
<button onClick={handleDeleteAccount}>Delete account</button>
{alert.modal}
</div>
)
}
For data prompts all you need is to resolve the promise by submitting the value to onSubmit
:
either a scalar, or more complex shapes wrapped into an object:
import { usePromiseModal } from '@prezly/react-promise-modal';
function MyApp() {
const prompt = usePromiseModal<string, { title: string }>(
(props) => <MyFilenamePromptModal {...props} />,
);
async function handleCreateFile() {
const filename = await prompt.invoke({ title: 'Please enter filename:' });
if (!filename) {
console.error('Filename is required');
return;
}
await api.createFile(filename);
}
return (
<div>
<button onClick={handleCreateFile}>Create new file</button>
{prompt.modal}
</div>
)
}
interface Props {
title: string;
show: boolean;
onSubmit: (filename: string) => void;
onDismiss: () => void;
}
function MyFilenamePromptModal({ title, show, onSubmit, onDismiss }: Props) {
const [filename, setFilename] = useState("Untitled.txt");
return (
// Use any modal implementation you want
<Modal>
<form onSubmit={() => onSubmit(filename)}>
<p>{title}</p>
<input autoFocus value={filename} onChange={(event) => setFilename(event.target.value)} />
<button variant="secondary" onClick={onDismiss}>Cancel</button>
<button variant="primary" type="submit">Confirm</button>
</form>
</Modal>
);
}
In addition to the three standard properties your modal render callback will always receive when rendered,
you can pass extra call-time properties. Declare them with the second generic type parameter of usePromiseModal()
,
and then pass to the invoke()
method:
import { usePromiseModal } from "@prezly/react-promise-modal";
const failureFeedback = usePromiseModal<undefined, { status: Status, failures: OperationFailure[] }>(
({ status, failures, show, onSubmit, onDismiss }) => (
<FailureModal status={status} failures={failures} show={show} onSubmit={onSubmit} onDismiss={onDismiss} />
),
);
// Invocation of the modal now requrires these additional properties:
async function handleFlakyOperation() {
const { status, failures } = await api.flakyOperation();
if (status !== 'success') {
await failureFeedback.invoke({ status, failures }); // Note: here we pass additional parameters call-time
}
}
Brought to you with :metal: by Prezly.
FAQs
The proper (and easy) way of doing modals in React. With Promises.
The npm package @prezly/react-promise-modal receives a total of 1,772 weekly downloads. As such, @prezly/react-promise-modal popularity was classified as popular.
We found that @prezly/react-promise-modal demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
AGENTS.md is a fast-growing open format giving AI coding agents a shared, predictable way to understand project setup, style, and workflows.
Security News
/Research
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.