Dialog
Display a modal dialog box.
#
Documentation
#
#
Usage
#
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@optiaxiom/react";
export function App() {
return (
<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
#
Controlled
#
Use the open
and defaultOpen
props to toggle between controlled and uncontrolled usage. And combine it with onOpenChange
to listen for changes to the state.
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@optiaxiom/react";
import { useState } from "react";
export function App() {
const [open, setOpen] = useState(false);
return (
<Dialog onOpenChange={setOpen} open={open}>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
#
Sizes
#
Use the size
prop to change the size of the dialog box.
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@optiaxiom/react";
import { type ComponentPropsWithRef } from "react";
export function App({
size,
}: Pick<ComponentPropsWithRef<typeof DialogContent>, "size">) {
return (
<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent size={size}>
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
#
Description
#
You can add accessible description to the modal using the DialogDescription
component.
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@optiaxiom/react";
export function App() {
return (
<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
<DialogDescription>
This is additional description of the modal
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose>Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
#
Customize trigger
#
By default we use the Button
component for the dialog trigger which accepts all of the existing button props.
We can also completely change the trigger by using asChild
and passing our own component.
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@optiaxiom/react";
import { IconRefresh } from "@tabler/icons-react";
export function App() {
return (
<Dialog>
<DialogTrigger
appearance="primary"
aria-label="Re-publish changes"
icon={<IconRefresh />}
/>
<DialogContent>
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
#
Form dialogs
#
Wrap dialog content with the DialogForm
component to use forms in dialogs.
import {
Button,
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogForm,
DialogHeader,
DialogTitle,
DialogTrigger,
Field,
Flex,
Input,
Textarea,
} from "@optiaxiom/react";
import { useState } from "react";
export function App() {
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
return (
<Dialog onOpenChange={loading ? undefined : setOpen} open={open}>
<DialogTrigger>Create new issue</DialogTrigger>
<DialogContent size="sm">
<DialogForm
onSubmit={(event) => {
event.preventDefault();
setLoading(true);
// use form data to perform a server action
setTimeout(() => {
setLoading(false);
setOpen(false);
}, 3000);
}}
>
<DialogHeader>
<DialogTitle>Create new issue</DialogTitle>
</DialogHeader>
<DialogBody>
<Flex>
<Field label="Title">
<Input name="title" required />
</Field>
<Field label="Description">
<Textarea name="description" required />
</Field>
</Flex>
</DialogBody>
<DialogFooter>
<DialogClose disabled={loading}>Cancel</DialogClose>
<Button
appearance="primary"
disabled={loading}
loading={loading}
type="submit"
>
Save
</Button>
</DialogFooter>
</DialogForm>
</DialogContent>
</Dialog>
);
}
#
Nested dialogs
#
Combine dialogs to show nested dialogs.
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@optiaxiom/react";
export function App() {
return (
<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<Dialog>
<DialogTrigger mr="auto">Open nested dialog</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<Dialog>
<DialogTrigger mr="auto">Open nested dialog</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
#
Nested alert dialogs
#
Combine Dialog
with AlertDialog
to show nested confirmation dialogs.
Use the onOpenChange
handler to trigger the nested callback instead of an explicit trigger.
Type something into the text field and then attempt to close the dialog:
import {
AlertDialog,
AlertDialogAction,
AlertDialogBody,
AlertDialogCancel,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
Button,
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogForm,
DialogHeader,
DialogTitle,
DialogTrigger,
Textarea,
} from "@optiaxiom/react";
import { useRef, useState } from "react";
export function App() {
const [open, setOpen] = useState(false);
const [alertOpen, setAlertOpen] = useState(false);
const textRef = useRef<HTMLTextAreaElement>(null);
return (
<Dialog
onOpenChange={(open) => {
if (!open && textRef.current?.value) {
setAlertOpen(true);
} else {
setOpen(open);
}
}}
open={open}
>
<DialogTrigger>Create new issue</DialogTrigger>
<DialogContent size="sm">
<DialogForm
onSubmit={(event) => {
event.preventDefault();
setOpen(false);
}}
>
<DialogHeader>
<DialogTitle>Create new issue</DialogTitle>
</DialogHeader>
<DialogBody>
<Textarea ref={textRef} required />
</DialogBody>
<DialogFooter>
<DialogClose>Cancel</DialogClose>
<Button appearance="primary">Save</Button>
</DialogFooter>
</DialogForm>
</DialogContent>
<AlertDialog onOpenChange={setAlertOpen} open={alertOpen}>
<AlertDialogContent onCloseAutoFocus={() => textRef.current?.focus()}>
<AlertDialogHeader>Discard issue?</AlertDialogHeader>
<AlertDialogBody>All unsaved changes will be lost.</AlertDialogBody>
<AlertDialogFooter>
<AlertDialogCancel />
<AlertDialogAction onClick={() => setOpen(false)}>
Yes, discard
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</Dialog>
);
}
#
Related
#
AlertDialog
Display a modal with important content that expects confirmation from the user.
#
Props
#
#
Dialog
#
Doesn't render its own HTML element.
Prop |
---|
defaultOpen The initial open state in uncontrolled mode. false | true |
onOpenChange Handler that is called when the open state changes. (open: boolean) => void |
open The open state in controlled mode. false | true |
#
DialogTrigger
#
Supports all Button props in addition to its own. Renders a <button>
element.
Prop |
---|
addonAfter Display content inside the button after ReactNode |
addonBefore Display content inside the button before ReactNode |
appearance Control the appearance by selecting between the different button types. "default" | "danger" | "primary" | "subtle" | "danger-outline" | "inverse" |
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
disabled Whether the button is disabled. false | true |
icon Display an icon before or after the button content or omit ReactNode |
iconOnly Whether button should have square shape. false | true |
iconPosition Control whether to show the icon before or after the button content. "end" | "start" |
loading Whether to show loading spinner inside the button. false | true |
size Control the size of the button. "sm" | "md" | "lg" |
#
DialogContent
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
onCloseAutoFocus Event handler called when auto-focusing on close. Can be prevented. (event: Event) => void |
onEscapeKeyDown Event handler called when the escape key is down. Can be prevented. (event: KeyboardEvent) => void |
onFocusOutside Event handler called when the focus moves outside of the (event: FocusOutsideEvent) => void |
onInteractOutside Event handler called when an interaction happens outside the (event: FocusOutsideEvent | PointerDownOutsideEvent) => void |
onOpenAutoFocus Event handler called when auto-focusing on open. Can be prevented. (event: Event) => void |
onPointerDownOutside Event handler called when the a (event: PointerDownOutsideEvent) => void |
size "sm" | "md" | "lg" | "fullscreen" Default: md |
transitionType "pop" | "fade" Default: fade |
#
DialogHeader
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
#
DialogTitle
#
Supports all Heading props in addition to its own. Renders an <h2>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
level Switch between the different h1-h6 levels. "1" | "2" | "3" | "4" | "6" | "5" |
lineClamp Truncate the text at specific number of lines. "1" | "2" | "3" | "4" |
truncate Whether to truncate the text and add an ellipsis at the end. false | true |
#
DialogActions
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
#
DialogDescription
#
Supports all Text props in addition to its own. Renders a <p>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
#
DialogBody
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
#
DialogFooter
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
#
DialogClose
#
Supports all Button props in addition to its own. Renders a <button>
element.
Prop |
---|
addonAfter Display content inside the button after ReactNode |
addonBefore Display content inside the button before ReactNode |
appearance Control the appearance by selecting between the different button types. "default" | "danger" | "primary" | "subtle" | "danger-outline" | "inverse" |
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details. false | true |
className string |
disabled Whether the button is disabled. false | true |
icon Display an icon before or after the button content or omit ReactNode |
iconOnly Whether button should have square shape. false | true |
iconPosition Control whether to show the icon before or after the button content. "end" | "start" |
loading Whether to show loading spinner inside the button. false | true |
size Control the size of the button. "sm" | "md" | "lg" Default: lg |
#
Changelog
#
#
0.1.0
#
- Added component