Dialog
Display a modal dialog box.
#
Documentation
#
#
Usage
#
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTrigger,
} from "@optiaxiom/react";
export function App() {
return (
<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogHeader>Modal Title</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}#
Anatomy
#
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogForm,
DialogHeader,
DialogTrigger,
} from "@optiaxiom/react";
export default () => (
<Dialog>
<DialogTrigger />
<DialogContent>
<DialogHeader />
<DialogBody />
<DialogFooter>
<DialogClose />
</DialogFooter>
<DialogForm>
<DialogBody />
<DialogFooter />
</DialogForm>
</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.
"use client";
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
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>Modal Title</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}#
Managed ALPHA
#
Use dialogkit.create() to create dialogs in managed mode. In managed mode you must omit the Dialog element and only send the DialogContent element and its children.
App.tsx
"use client";
import { Button } from "@optiaxiom/react";
import { dialogkit } from "@optiaxiom/react/unstable";
import { CreateDialog } from "./CreateDialog";
export function App() {
return (
<Button onClick={() => dialogkit.create(<CreateDialog />)}>
Open Dialog
</Button>
);
}#
Sizes
#
Use the size prop to change the size of the dialog box.
"use client";
import {
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
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>Modal Title</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 description prop on DialogHeader component.
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTrigger,
} from "@optiaxiom/react";
export function App() {
return (
<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogHeader description="This is additional text to describe the modal">
Modal Title
</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,
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>Modal Title</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<DialogClose appearance="primary">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}#
Form dialogs
#
Wrap DialogBody and DialogFooter with the DialogForm component to use forms in dialogs.
"use client";
import {
Button,
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogForm,
DialogHeader,
DialogTrigger,
Field,
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">
<DialogHeader>Create new issue</DialogHeader>
<DialogForm
onSubmit={(event) => {
event.preventDefault();
setLoading(true);
// use form data to perform a server action
setTimeout(() => {
setLoading(false);
setOpen(false);
}, 3000);
}}
>
<DialogBody>
<Field label="Title">
<Input autoFocus name="title" required />
</Field>
<Field label="Description">
<Textarea name="description" required />
</Field>
</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,
DialogTrigger,
} from "@optiaxiom/react";
export function App() {
return (
<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>Modal Title</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<Dialog>
<DialogTrigger mr="auto">Open nested dialog</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>Modal Title</DialogHeader>
<DialogBody>This is the modal body</DialogBody>
<DialogFooter>
<Dialog>
<DialogTrigger mr="auto">Open nested dialog</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>Modal Title</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 cancel the dialog:
"use client";
import {
Alert,
AlertDialog,
AlertDialogAction,
AlertDialogBody,
AlertDialogCancel,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
Button,
Dialog,
DialogBody,
DialogClose,
DialogContent,
DialogFooter,
DialogForm,
DialogHeader,
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">
<DialogHeader>Create new issue</DialogHeader>
<DialogForm
onSubmit={(event) => {
event.preventDefault();
setOpen(false);
}}
>
<DialogBody>
<Alert intent="warning">
Type something into the text field and then attempt to cancel the
dialog:
</Alert>
<Textarea autoFocus 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>No, keep editing</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 |
|---|
defaultOpenThe initial open state in uncontrolled mode.
Default: |
onOpenChangeHandler that is called when the open state changes.
|
openThe open state in controlled mode.
|
#
DialogTrigger
#
Supports all Button props in addition to its own. Renders a <button> element.
Prop |
|---|
addonAfterDisplay content inside the button after
|
addonBeforeDisplay content inside the button before
|
appearanceControl the appearance by selecting between the different button types.
|
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
disabledWhether the button is disabled.
|
iconDisplay an icon before or after the button content or omit
|
iconPositionControl whether to show the icon before or after the button content.
|
loadingWhether to show loading spinner inside the button.
|
sizeControl the size of the button.
|
squareWhether button should have square shape.
|
#
DialogContent
#
Supports all Box props in addition to its own. Renders a <div> element.
Prop |
|---|
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
onCloseAutoFocusEvent handler called when auto-focusing on close. Can be prevented.
|
onEscapeKeyDownEvent handler called when the escape key is down. Can be prevented.
|
onFocusOutsideEvent handler called when the focus moves outside of the
|
onInteractOutsideEvent handler called when an interaction happens outside the
|
onOpenAutoFocusEvent handler called when auto-focusing on open. Can be prevented.
|
onPointerDownOutsideEvent handler called when the a
|
sizeControl the size/width of the dialog box.
Default: |
#
DialogHeader
#
Supports all Box props in addition to its own. Renders a <div> element.
Prop |
|---|
addonAfterDisplay content inside the header after
|
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
descriptionAdd secondary text after the primary title.
|
#
DialogForm
#
Supports all Box props in addition to its own. Renders a <form> element.
Prop |
|---|
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
#
DialogBody
#
Supports all Box props in addition to its own. Renders a <div> element.
Prop |
|---|
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
#
DialogFooter
#
Supports all Box props in addition to its own. Renders a <div> element.
Prop |
|---|
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
#
DialogClose
#
Supports all Button props in addition to its own. Renders a <button> element.
Prop |
|---|
addonAfterDisplay content inside the button after
|
addonBeforeDisplay content inside the button before
|
appearanceControl the appearance by selecting between the different button types.
Default: |
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
disabledWhether the button is disabled.
|
iconDisplay an icon before or after the button content or omit
|
iconPositionControl whether to show the icon before or after the button content.
|
loadingWhether to show loading spinner inside the button.
|
sizeControl the size of the button.
|
squareWhether button should have square shape.
|
#
Accessibility
#
#
Keyboard interactions
#
Key | Description |
|---|---|
Space Enter | When focus is on DialogTrigger, opens the dialog. |
| Esc | Closes the dialog and moves focus to DialogTrigger. |
#
Changelog
#
#
1.6.7
#
-
Introduced dialogkit for easier management of dialogs.
import { DialogContent } from "@optiaxiom/react"; import { dialogkit } from "@optiaxiom/react/unstable"; dialogkit.create(<DialogContent>{/* ... */}</DialogContent>);
#
0.1.0
#
- Added component