Displays a modal window above the page contents.
<Dialog.Root> <Dialog.Trigger> <Button>Open</Button> </Dialog.Trigger> <Dialog.Content> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Flex direction="column" gap="4"> <label> <Text as="div" size="2" mb="2" weight="bold"> Name </Text> <TextField.Root defaultValue="Jane Doe" placeholder="Enter your full name" /> </label> <label> <Text as="div" size="2" mb="2" weight="bold"> </Text> <TextField.Root defaultValue="jane@foo-corp.com" placeholder="Enter your email" /> </label> </Flex> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root>
This component inherits parts and props from the Radix Dialog primitive. View source
Contains content to be rendered in the open dialog. This component is based on the div
element.
Prop | Type | Default |
---|---|---|
size | '1' | '2' | '3' | '4' | '5' | '6' |
The size
prop will map to the following widths:
Size | Max Width |
---|---|
1 | 430px |
2 | 530px |
3 | 600px |
4 | 680px |
5 | 780px |
6 | 900px |
Prop | Type | Default |
---|---|---|
title | React.ReactNode | required |
description | React.ReactNode | |
error | React.ReactNode | |
children | React.ReactNode | null |
Contains the main content of the dialog – it has a built-in scroll area that is only visible when the content is too big to fit in the dialog.
The Title
component is deprecated and it should be used only on very specific cases. Use the title
prop instead.
An accessible title that is announced when the dialog is opened. This part is based on the Heading component with a pre-defined font size and leading trim on top.
The Description
component is deprecated and it should be used only on very specific cases. Use the description
prop instead.
An optional accessible description that is announced when the dialog is opened. This part is based on the Text component with a pre-defined font size.
If you want to remove the description entirely, remove this part and pass aria-describedby={undefined}
to Dialog.Content
.
Use the size
prop in the Content
component to control the maxWidth
of the dialog.
If you have a very specific case, you can still pass a custom maxWidth
prop to override the size.
<Flex gap="4"> <Dialog.Root> <Dialog.Trigger> <Button>Size 1</Button> </Dialog.Trigger> <Dialog.Content size="1"> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Text as="p"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root> <Dialog.Root> <Dialog.Trigger> <Button>Size 2</Button> </Dialog.Trigger> <Dialog.Content size="2"> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Text as="p"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root> <Dialog.Root> <Dialog.Trigger> <Button>Size 3</Button> </Dialog.Trigger> <Dialog.Content size="3"> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Text as="p"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root> <Dialog.Root> <Dialog.Trigger> <Button>Size 4</Button> </Dialog.Trigger> <Dialog.Content size="4"> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Text as="p"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root> <Dialog.Root> <Dialog.Trigger> <Button>Size 5</Button> </Dialog.Trigger> <Dialog.Content size="5"> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Text as="p"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root> <Dialog.Root> <Dialog.Trigger> <Button>Size 6</Button> </Dialog.Trigger> <Dialog.Content size="6"> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Text as="p"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root> <Dialog.Root> <Dialog.Trigger> <Button>Fit</Button> </Dialog.Trigger> <Dialog.Content> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." /> <Dialog.Body> <Text as="p"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root> </Flex>
Use the Inset component to create a container that ignores the Content part padding. If needed, you can recreate the original padding by setting the Inset part’s padding props to "current"
.
<Dialog.Root> <Dialog.Trigger> <Button>Open</Button> </Dialog.Trigger> <Dialog.Content width="500px"> <Dialog.Header title="Custom domain" description="Customize the domain used to authenticate users." /> <Dialog.Body> <Box> <Label mb="1">Auth domain</Label> <TextField.Root disabled defaultValue="auth.workos.com" /> </Box> </Dialog.Body> <Inset p="current" side="bottom" style={{ backgroundColor: 'var(--gray-a1)', borderTop: '1px solid var(--gray-a4)', }} > <Dialog.Footer> <Text size="2" color="gray" mr="auto"> <Link href="https://example.com" color="gray" highContrast> Upgrade to Enterprise </Link>{' '} to enable this feature </Text> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button disabled>Save</Button> </Dialog.Close> </Dialog.Footer> </Inset> </Dialog.Content> </Dialog.Root>
Whenever the body of the dialog is bigger than the dialog itself, it will show a scrollbar automatically.
<Dialog.Root> <Dialog.Trigger> <Button>Open</Button> </Dialog.Trigger> <Dialog.Content size="3"> <Dialog.Header title="Heading" description="Subtitle" /> <Dialog.Body> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p" mb="4"> Typographers are concerned with legibility insofar as it is their job to select the correct font to use. Brush Script is an example of a font containing many characters that might be difficult to distinguish. The selection of cases influences the legibility of typography because using only uppercase letters (all-caps) reduces legibility. </Text> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p" mb="4"> Typographers are concerned with legibility insofar as it is their job to select the correct font to use. Brush Script is an example of a font containing many characters that might be difficult to distinguish. The selection of cases influences the legibility of typography because using only uppercase letters (all-caps) reduces legibility. </Text> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p"> Typographers are concerned with legibility insofar as it is their job to select the correct font to use. Brush Script is an example of a font containing many characters that might be difficult to distinguish. The selection of cases influences the legibility of typography because using only uppercase letters (all-caps) reduces legibility. </Text> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button disabled>Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root>
<Dialog.Root> <Dialog.Trigger> <Button>Open</Button> </Dialog.Trigger> <Dialog.Content maxWidth="500px"> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you’re done." error="Something went wrong. Try again later." /> <Dialog.Body> <Flex direction="column" gap="4"> <label> <Text as="div" size="2" mb="2" weight="bold"> Name </Text> <TextField.Root defaultValue="Jane Doe" placeholder="Enter your full name" /> </label> <label> <Text as="div" size="2" mb="2" weight="bold"> </Text> <TextField.Root defaultValue="jane@foo-corp.com" placeholder="Enter your email" /> </label> </Flex> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root>
This is now deprecated. You should combine the Header
, Body
and Footer
parts to create a scrollable content.
So this example is only for reference as most of our dialogs in the dashboard still use this type of dialog.
<Dialog.Root> <Dialog.Trigger> <Button>Open</Button> </Dialog.Trigger> <Dialog.Content size="3"> <Dialog.Title>Heading</Dialog.Title> <Dialog.Description>Subtitle</Dialog.Description> <Box mt="4"> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p" mb="4"> Typographers are concerned with legibility insofar as it is their job to select the correct font to use. Brush Script is an example of a font containing many characters that might be difficult to distinguish. The selection of cases influences the legibility of typography because using only uppercase letters (all-caps) reduces legibility. </Text> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p" mb="4"> Typographers are concerned with legibility insofar as it is their job to select the correct font to use. Brush Script is an example of a font containing many characters that might be difficult to distinguish. The selection of cases influences the legibility of typography because using only uppercase letters (all-caps) reduces legibility. </Text> <Text as="p" mb="4"> Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts. </Text> <Text as="p" mb="4"> Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility. </Text> <Text as="p"> Typographers are concerned with legibility insofar as it is their job to select the correct font to use. Brush Script is an example of a font containing many characters that might be difficult to distinguish. The selection of cases influences the legibility of typography because using only uppercase letters (all-caps) reduces legibility. </Text> </Box> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button disabled>Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root>
There are a couple ways to use tables inside dialogs.
Inset
component without Table.Root
for an edge-to-edge designTable.Root
for a contained table look.
<Dialog.Root> <Dialog.Trigger> <Button>Open</Button> </Dialog.Trigger> <Dialog.Content> <Dialog.Header title="Edit profile" description="Make changes to your profile here. Click save when you're done." /> <Dialog.Body> <Heading size="3" mb="2" as="h3"> With inset </Heading> <Inset side="x"> <Table.Content> <Table.Header> <Table.Row> <Table.ColumnHeader>Device</Table.ColumnHeader> <Table.ColumnHeader>Location</Table.ColumnHeader> </Table.Row> </Table.Header> <Table.Body> <Table.Row> <Table.RowHeader>iPhone Xs</Table.RowHeader> <Table.Cell>Sant Cugat del Vallès, Spain</Table.Cell> </Table.Row> <Table.Row> <Table.RowHeader>MacBook Pro 15″</Table.RowHeader> <Table.Cell>Sant Cugat del Vallès, Spain</Table.Cell> </Table.Row> </Table.Body> </Table.Content> </Inset> <Heading size="3" mb="2" mt="6" as="h3"> Without inset and with Table.Root </Heading> <Table.Root> <Table.Content> <Table.Header> <Table.Row> <Table.ColumnHeader>Device</Table.ColumnHeader> <Table.ColumnHeader>Location</Table.ColumnHeader> </Table.Row> </Table.Header> <Table.Body> <Table.Row> <Table.RowHeader>iPhone Xs</Table.RowHeader> <Table.Cell>Sant Cugat del Vallès, Spain</Table.Cell> </Table.Row> <Table.Row> <Table.RowHeader>MacBook Pro 15″</Table.RowHeader> <Table.Cell>Sant Cugat del Vallès, Spain</Table.Cell> </Table.Row> </Table.Body> </Table.Content> </Table.Root> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Dialog.Close> <Button color="purple">Save</Button> </Dialog.Close> </Dialog.Footer> </Dialog.Content> </Dialog.Root>
Dialogs commonly contain forms for creating or editing resources. These patterns demonstrate proper state management for loading, dirty checking, and error handling using React Hook Form.
Demonstrates how to display form submit errors within dialogs.
() => { const [isOpen, setIsOpen] = React.useState(false); const form = useForm({ resolver: zodResolver( z.object({ email: z .string() .min(1, 'Email is required') .email('Invalid email address'), }), ), defaultValues: { email: '' }, }); React.useEffect(() => { if (isOpen) { form.reset(); form.clearErrors(); } }, [isOpen, form]); const onSubmit = async (data) => { try { await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate server error if (data.email === 'taken@example.com') { form.setError('root', { message: 'This email address is already in use', }); return; } console.log('Success:', data); setIsOpen(false); } catch (error) { form.setError('root', { message: 'Something went wrong' }); } }; return ( <Dialog.Root open={isOpen} onOpenChange={setIsOpen}> <Dialog.Trigger> <Button>Test error handling</Button> </Dialog.Trigger> <Dialog.Content size="2"> <FormProvider {...form}> <Dialog.Header title="Test form errors" description="Try 'taken@example.com' to see a server error" error={form.formState.errors.root?.message} /> <Dialog.Body> <form id="test-error-form" noValidate onSubmit={form.handleSubmit(onSubmit)} > <Flex direction="column" gap="4"> <label> <Text as="div" size="2" mb="2" weight="bold"> </Text> <TextField.Root placeholder="Enter your email" {...form.register('email')} invalid={!!form.formState.errors.email} /> {form.formState.errors.email && ( <Text size="2" color="red" mt="2"> {form.formState.errors.email.message} </Text> )} </label> </Flex> </form> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Button type="submit" form="test-error-form" color="purple" loading={ form.formState.isSubmitting || form.formState.isSubmitSuccessful } > Submit </Button> </Dialog.Footer> </FormProvider> </Dialog.Content> </Dialog.Root> ); };
The loading state should always be true when the form is submitted or when the submission has succeeded AND the dialog has been closed
tsx <Button type="submit" loading={form.formState.isSubmitting || form.formState.isSubmitSuccessful} > Save changes </Button>
For edit forms only, keep the submit button disabled when the form is not dirty:
<Button type="submit" disabled={!form.formState.isDirty} loading={form.formState.isSubmitting} > Save changes </Button>
Form reset on dialog open
React.useEffect(() => { if (isOpen) { form.reset(); form.clearErrors(); } }, [isOpen, form]);
Place the <form>
tag inside Dialog.Body
and use the form
attribute on submit buttons. Display form-level errors using the Dialog.Header
error
prop:
<Dialog.Content> <Dialog.Header title="Form title" error={form.formState.errors.root?.message} /> <Dialog.Body> <form id="my-form" onSubmit={form.handleSubmit(onSubmit)}> {/* form fields */} </form> </Dialog.Body> <Dialog.Footer> <Button type="submit" form="my-form"> Submit </Button> </Dialog.Footer> </Dialog.Content>
This approach:
Use your resolver (like Zod) for field validation, and display errors inline.
For simple forms (using register
):
<label> <Text as="div" size="2" mb="2" weight="bold"> </Text> <TextField.Root {...form.register('email')} placeholder="Enter your email" invalid={!!form.formState.errors.email} /> {form.formState.errors.email && ( <Text size="2" color="red" mt="2"> {form.formState.errors.email.message} </Text> )} </label>
For edit forms or when you need more control (using Controller
):
<Controller name="email" control={form.control} render={({ field, fieldState }) => ( <label> <Text as="div" size="2" mb="2" weight="bold"> </Text> <TextField.Root {...field} placeholder="Enter your email" invalid={!!fieldState.error} /> {fieldState.error && ( <Text size="2" as="p" color="red" mt="2"> {fieldState.error.message} </Text> )} </label> )} />
A complete example showing how to create a dialog for adding new resources with proper form reset and loading states.
() => { const [isOpen, setIsOpen] = React.useState(false); const form = useForm({ resolver: zodResolver( z.object({ name: z.string().min(1, 'Name is required'), email: z.string().min(1, 'Email is required').email('Invalid email'), }), ), defaultValues: { name: '', email: '' }, }); // Reset form when dialog opens React.useEffect(() => { if (isOpen) { form.reset(); form.clearErrors(); } }, [isOpen, form]); const onSubmit = async (data) => { try { // Simulate API call await new Promise((resolve) => setTimeout(resolve, 2000)); console.log('Creating resource:', data); setIsOpen(false); } catch (error) { form.setError('root', { message: 'Failed to create user' }); } }; return ( <Dialog.Root open={isOpen} onOpenChange={setIsOpen}> <Dialog.Trigger> <Button>Create user</Button> </Dialog.Trigger> <Dialog.Content size="2"> <FormProvider {...form}> <Dialog.Header title="Create user" description="Enter the user's information below" error={form.formState.errors.root?.message} /> <Dialog.Body> <form id="add-resource-form" noValidate onSubmit={form.handleSubmit(onSubmit)} > <Flex direction="column" gap="4"> <Controller name="name" control={form.control} render={({ field, fieldState }) => ( <label> <Text as="div" size="2" mb="2" weight="bold"> Name </Text> <TextField.Root {...field} placeholder="Enter the name" invalid={!!fieldState.error} /> {fieldState.error && ( <Text size="2" as="p" color="red" mt="2"> {fieldState.error.message} </Text> )} </label> )} /> <Controller name="email" control={form.control} render={({ field, fieldState }) => ( <label> <Text as="div" size="2" mb="2" weight="bold"> </Text> <TextField.Root {...field} placeholder="Enter the email" invalid={!!fieldState.error} /> {fieldState.error && ( <Text size="2" as="p" color="red" mt="2"> {fieldState.error.message} </Text> )} </label> )} /> </Flex> </form> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Button type="submit" form="add-resource-form" color="purple" loading={ form.formState.isSubmitting || form.formState.isSubmitSuccessful } > Create user </Button> </Dialog.Footer> </FormProvider> </Dialog.Content> </Dialog.Root> ); };
For editing existing resources, the submit button should be disabled when the form is not dirty (no changes made).
() => { const existingResource = { name: 'John Adams', email: 'john.adams@example.com', }; const [isOpen, setIsOpen] = React.useState(false); const form = useForm({ resolver: zodResolver( z.object({ name: z.string().min(1, 'Name is required'), email: z.string().min(1, 'Email is required').email('Invalid email'), }), ), defaultValues: existingResource, }); // Reset form when dialog opens React.useEffect(() => { if (isOpen) { form.reset(); form.clearErrors(); } }, [isOpen, form]); const onSubmit = async (data) => { try { // Simulate API call await new Promise((resolve) => setTimeout(resolve, 2000)); console.log('Updating resource:', data); setIsOpen(false); } catch (error) { form.setError('root', { message: 'Failed to update user' }); } }; return ( <Dialog.Root open={isOpen} onOpenChange={setIsOpen}> <Dialog.Trigger> <Button>Edit user</Button> </Dialog.Trigger> <Dialog.Content size="2"> <FormProvider {...form}> <Dialog.Header title="Edit user" description="Update user information" error={form.formState.errors.root?.message} /> <Dialog.Body> <form id="edit-resource-form" noValidate onSubmit={form.handleSubmit(onSubmit)} > <Flex direction="column" gap="4"> <Controller name="name" control={form.control} render={({ field, fieldState }) => ( <label> <Text as="div" size="2" mb="2" weight="bold"> Name </Text> <TextField.Root {...field} placeholder="Enter the name" invalid={!!fieldState.error} /> {fieldState.error && ( <Text size="2" as="p" color="red" mt="2"> {fieldState.error.message} </Text> )} </label> )} /> <Controller name="email" control={form.control} render={({ field, fieldState }) => ( <label> <Text as="div" size="2" mb="2" weight="bold"> </Text> <TextField.Root {...field} placeholder="Enter the email" invalid={!!fieldState.error} /> {fieldState.error && ( <Text size="2" as="p" color="red" mt="2"> {fieldState.error.message} </Text> )} </label> )} /> </Flex> </form> </Dialog.Body> <Dialog.Footer> <Dialog.Close> <Button>Cancel</Button> </Dialog.Close> <Button type="submit" form="edit-resource-form" color="purple" disabled={!form.formState.isDirty} loading={ form.formState.isSubmitting || form.formState.isSubmitSuccessful } > Save changes </Button> </Dialog.Footer> </FormProvider> </Dialog.Content> </Dialog.Root> ); };