Dialog
Dialog Primitive
Terminal window
~/components/ui/dialog.tsx
Demo
A modal dialog that interrupts the user with important content and expects a response.
Installation
npx @react-native-reusables/cli@latest add dialog
Copy/paste the following code to ~/components/ui/dialog.tsx
:
import * as DialogPrimitive from '@rn-primitives/dialog';import * as React from 'react';import { Platform, StyleSheet, View, type ViewProps } from 'react-native';import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';import { X } from '~/lib/icons/X';import { cn } from '~/lib/utils';
const Dialog = DialogPrimitive.Root;
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close;
const DialogOverlayWeb = React.forwardRef<DialogPrimitive.OverlayRef, DialogPrimitive.OverlayProps>( ({ className, ...props }, ref) => { const { open } = DialogPrimitive.useRootContext(); return ( <DialogPrimitive.Overlay className={cn( 'bg-black/80 flex justify-center items-center p-2 absolute top-0 right-0 bottom-0 left-0', open ? 'web:animate-in web:fade-in-0' : 'web:animate-out web:fade-out-0', className )} {...props} ref={ref} /> ); });
DialogOverlayWeb.displayName = 'DialogOverlayWeb';
const DialogOverlayNative = React.forwardRef< DialogPrimitive.OverlayRef, DialogPrimitive.OverlayProps>(({ className, children, ...props }, ref) => { return ( <DialogPrimitive.Overlay style={StyleSheet.absoluteFill} className={cn('flex bg-black/80 justify-center items-center p-2', className)} {...props} ref={ref} > <Animated.View entering={FadeIn.duration(150)} exiting={FadeOut.duration(150)}> <>{children}</> </Animated.View> </DialogPrimitive.Overlay> );});
DialogOverlayNative.displayName = 'DialogOverlayNative';
const DialogOverlay = Platform.select({ web: DialogOverlayWeb, default: DialogOverlayNative,});
const DialogContent = React.forwardRef< DialogPrimitive.ContentRef, DialogPrimitive.ContentProps & { portalHost?: string }>(({ className, children, portalHost, ...props }, ref) => { const { open } = DialogPrimitive.useRootContext(); return ( <DialogPortal hostName={portalHost}> <DialogOverlay> <DialogPrimitive.Content ref={ref} className={cn( 'max-w-lg gap-4 border border-border web:cursor-default bg-background p-6 shadow-lg web:duration-200 rounded-lg', open ? 'web:animate-in web:fade-in-0 web:zoom-in-95' : 'web:animate-out web:fade-out-0 web:zoom-out-95', className )} {...props} > {children} <DialogPrimitive.Close className={ 'absolute right-4 top-4 p-0.5 web:group rounded-sm opacity-70 web:ring-offset-background web:transition-opacity web:hover:opacity-100 web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2 web:disabled:pointer-events-none' } > <X size={Platform.OS === 'web' ? 16 : 18} className={cn('text-muted-foreground', open && 'text-accent-foreground')} /> </DialogPrimitive.Close> </DialogPrimitive.Content> </DialogOverlay> </DialogPortal> );});DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({ className, ...props }: ViewProps) => ( <View className={cn('flex flex-col gap-1.5 text-center sm:text-left', className)} {...props} />);DialogHeader.displayName = 'DialogHeader';
const DialogFooter = ({ className, ...props }: ViewProps) => ( <View className={cn('flex flex-col-reverse sm:flex-row sm:justify-end gap-2', className)} {...props} />);DialogFooter.displayName = 'DialogFooter';
const DialogTitle = React.forwardRef<DialogPrimitive.TitleRef, DialogPrimitive.TitleProps>( ({ className, ...props }, ref) => ( <DialogPrimitive.Title ref={ref} className={cn( 'text-lg native:text-xl text-foreground font-semibold leading-none tracking-tight', className )} {...props} /> ));DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = React.forwardRef< DialogPrimitive.DescriptionRef, DialogPrimitive.DescriptionProps>(({ className, ...props }, ref) => ( <DialogPrimitive.Description ref={ref} className={cn('text-sm native:text-base text-muted-foreground', className)} {...props} />));DialogDescription.displayName = DialogPrimitive.Description.displayName;
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger,};
Usage
import * as React from 'react';import { Button } from '~/components/ui/button';import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger,} from '~/components/ui/dialog';import { Text } from '~/components/ui/text';
function Example() { return ( <Dialog> <DialogTrigger asChild> <Button variant='outline'> <Text>Edit Profile</Text> </Button> </DialogTrigger> <DialogContent className='sm:max-w-[425px]'> <DialogHeader> <DialogTitle>Edit profile</DialogTitle> <DialogDescription> Make changes to your profile here. Click save when you're done. </DialogDescription> </DialogHeader> <DialogFooter> <DialogClose asChild> <Button> <Text>OK</Text> </Button> </DialogClose> </DialogFooter> </DialogContent> </Dialog> );}
Props
Dialog
Extends View
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
open | boolean | (optional) |
onOpenChange | (value: boolean) => void | (optional) |
defaultOpen | boolean | (optional) |
DialogTrigger
Extends Pressable
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
DialogOverlay
Extends View
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
forceMount | true | undefined; | (optional) |
closeOnPress | boolean | (optional) |
DialogPortal
Prop | Type | Note |
---|---|---|
children* | React.ReactNode | |
forceMount | true | undefined | (optional) |
hostName | string | Web Only (optional) |
container | HTMLElement | null | undefined | Web Only (optional) |
DialogContent
Extends View
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
forceMount | true | undefined | (optional) |
alignOffset | number | Native Only (optional) |
insets | Insets | Native Only (optional) |
avoidCollisions | boolean | Native Only (optional) |
align | ’start’ | ‘center’ | ‘end’ | Native Only (optional) |
side | ’top’ | ‘bottom’ | Native Only (optional) |
sideOffset | number | Native Only (optional) |
disablePositioningStyle | boolean | Native Only (optional) |
onOpenAutoFocus | (ev: Event) => void | Web Only (optional) |
onCloseAutoFocus | (ev: Event) => void | Web Only (optional) |
onEscapeKeyDown | (ev: Event) => void | Web Only (optional) |
onInteractOutside | (ev: Event) => void | Web Only (optional) |
onPointerDownOutside | (ev: Event) => void | Web Only (optional) |
DialogHeader
Extends View
props
DialogTitle
Extends Text
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
DialogDescription
Extends Text
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
DialogFooter
Extends View
props
DialogClose
Extends Pressable
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |