Migration Guide
This guide explains how to migrate existing modals to hiraku.
Basic Migration Pattern
Before
tsx
import * as Dialog from "@radix-ui/react-dialog";
function ConfirmDialog({ isOpen, onClose, onConfirm, message }) {
return (
<Dialog.Root open={isOpen} onOpenChange={onClose}>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title>Confirm</Dialog.Title>
<p>{message}</p>
<button onClick={onClose}>Cancel</button>
<button onClick={onConfirm}>OK</button>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}After
Simply remove Dialog.Root and create a controller:
tsx
import { createDialog } from "@hirotoshioi/hiraku";
function ConfirmDialog({ message }: { message: string }) {
return (
// Dialog.Root is not needed! hiraku wraps it automatically
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title>Confirm</Dialog.Title>
<p>{message}</p>
<button onClick={() => confirmDialog.close({ role: "cancel" })}>
Cancel
</button>
<button onClick={() => confirmDialog.close({ data: true, role: "confirm" })}>
OK
</button>
</Dialog.Content>
</Dialog.Portal>
);
}
export const confirmDialog = createDialog(ConfirmDialog).returns<boolean>();Updating Usage Sites
Before
tsx
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>Open</button>
<ConfirmDialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
onConfirm={() => {
console.log("Confirmed");
setIsOpen(false);
}}
message="Are you sure you want to delete?"
/>
</>
);
}After
tsx
import { confirmDialog } from "./modals/confirm-dialog";
function App() {
const handleClick = async () => {
await confirmDialog.open({ message: "Are you sure you want to delete?" });
const result = await confirmDialog.onDidClose();
if (result.role === "confirm") {
console.log("Confirmed");
}
};
return <button onClick={handleClick}>Open</button>;
}Migration Steps
- Add
<ModalProvider>to the root of your app - Remove
Dialog.Root - Create a controller with
createDialog() - Remove
isOpen/onCloseprops and usecontroller.close()instead - Remove
useStatefrom usage sites and import the controller