Ariakit
/
This site is under construction Subscribe to updates

Dialog with Next.js App Router

Using Next.js Parallel Routes to create an accessible modal Dialog that is rendered on the server and controlled by the URL, with built-in focus management.

Open in new tab
import Link from "next/link.js";
export default function Page() {
return (
<Link href="/previews/dialog-next-router/login" className="button">
Login
</Link>
);
}

Controlling the Dialog state

To control the open state, you can pass the open and setOpen props to useDialogStore. These props allow you to synchronize the dialog state with other state sources, such as the browser history.

In this example, since the dialog is only rendered when the route matches, we can pass open: true to the store so that the dialog is always open. Then, we can use setOpen to navigate back when the dialog is closed:

const router = useRouter();
const dialog = Ariakit.useDialogStore({
open: true,
setOpen(open) {
if (!open) {
router.push("/previews/dialog-next-router");
}
},
});

You can learn more about controlled state on the Component stores guide.

Restoring focus on hide

When the dialog is closed, the focus is automatically returned to the element that was previously focused before opening the dialog. Typically, this is the element that triggered the dialog. However, in cases where a user navigates to the modal URL directly, there is no element to focus on hide.

To handle this scenario, the autoFocusOnHide prop can be used to specify a fallback element to focus on hide:

const pathname = usePathname();
<Dialog
autoFocusOnHide={(element) => {
if (!element) {
document.querySelector(`[href="${pathname}"]`)?.focus();
}
return true;
}}
>