Appearance
Handling multiple dialogs
The Privy modal is an HTML <dialog>
element that will appear in the foreground of your app when opened.
If your app makes use of dialog components (most commonly, for modals and pop-ups), you may encounter issues with the Privy dialog interfering with those from your app.
When using other non-Privy dialog elements within your app, we generally recommend:
- Avoid UIs that involve a modal overlaying another modal. This can be a confusing and visually jarring experience for users, especially since users can only interact with a single modal at a time.
- Use the
Dialog
component fromheadless-ui
, as it has the best compatibility with UI components and HTML elements from third-party libraries like Privy.
Radix UI dialogs
If your app uses the Dialog
component from Radix UI, we suggest making the following modifications to the default Dialog
component:
- Prevent the default behavior of the Radix dialog closing when the user clicks outside of it, via the
onPointerDownOutside
prop of theDialog.Content
component. - Prevent the default behavior of the Radix dialog always trapping the browser's focus (even if other dialogs are opened), by wrapping your
Dialog.Content
with theFocusScope
component from the@radix-ui/react-focus-scope
library. In thisFocusScope
component, you should set the proptrapped
tofalse
. See this GitHub discussion for more info!
Altogether, the modifications to a Dialog
component might look as follows:
tsx
import * as Dialog from '@radix-ui/react-dialog';
import {FocusScope} from '@radix-ui/react-focus-scope';
<Dialog.Root>
...
<Dialog.Portal>
<Dialog.Overlay />
{/* This wrapper prevents the Radix dialog from stealing focus away from other dialogs in the page. */}
<FocusScope trapped={false}>
{/* The `onPointerDownOutside` handler prevents Radix from closing the dialog when the user clicks outside. */}
<Dialog.Content
onPointerDownOutside={(e) => e.preventDefault()}
/>
...
</Dialog.Content>
</FocusScope>
</Dialog.Portal>
<Dialog.Root>