# Dialog

Dialogs are windows containing contextual information, tasks, or workflows that appear over the user interface.
Depending on the kind of Dialog, further interactions may be blocked until the Dialog is acknowledged.

```tsx
import {Dialog, DialogTrigger, Button, ButtonGroup, Heading, Content, Footer, Checkbox, Image, Form, TextField} from '@react-spectrum/s2';
import heroImage from 'url:./assets/preview.png';

function Example(props) {
  return (
    <DialogTrigger>
      <Button variant="primary">Open Dialog</Button>
      {/*- begin focus -*/}
      <Dialog {...props}>
        {({close}) => (
          <>
            <Image slot="hero" src={heroImage} />
            <Heading slot="title">Subscribe to our newsletter</Heading>
            <Content>
              <p>Enter your information to subscribe to our newsletter and receive updates about new features and announcements.</p>
              <Form>
                <TextField label="Name" />
                <TextField label="Email" type="email" />
              </Form>
            </Content>
            <Footer>
              <Checkbox>Don't show this again</Checkbox>
            </Footer>
            <ButtonGroup>
              <Button onPress={close} variant="secondary">Cancel</Button>
              <Button onPress={close} variant="accent">Subscribe</Button>
            </ButtonGroup>
          </>
        )}
      </Dialog>
      {/*- end focus -*/}
    </DialogTrigger>
  );
}
```

## Content

Dialogs are windows containing contextual information, tasks, or workflows that appear over the user interface. Spectrum includes several pre-defined dialog components with layouts for specific use cases, or you can use `CustomDialog` to create a custom layout.

### Standard Dialog

Use `Dialog` for standard dialog layouts. It supports `Image`, `Heading`, `Header`, `Content`, `Footer`, and `ButtonGroup` slots. Dismissible dialogs replace their `ButtonGroup` with a close button.

```tsx
import {Dialog, DialogTrigger, Button, ButtonGroup, Heading, Header, Content, Footer, Checkbox, Image, Form, TextField} from '@react-spectrum/s2';
import heroImage from 'url:./assets/preview.png';

function Example(props) {
  return (
    <DialogTrigger>
      <Button variant="primary">Open Dialog</Button>
      {/*- begin focus -*/}
      <Dialog {...props}>
        {({close}) => (
          <>
            <Image slot="hero" src={heroImage} />
            <Heading slot="title">Dialog Title</Heading>
            <Header>Header</Header>
            <Content>
              <p>Standard dialog description. This should briefly communicate any additional information or context about the standard dialog title, to help users make one of the decisions offered by the buttons. Make it no more than a few short sentences.</p>
            </Content>
            <Footer>
              <Checkbox>Don't show this again</Checkbox>
            </Footer>
            <ButtonGroup>
              <Button onPress={close} variant="secondary">Cancel</Button>
              <Button onPress={close} variant="accent">Subscribe</Button>
            </ButtonGroup>
          </>
        )}
      </Dialog>
      {/*- end focus -*/}
    </DialogTrigger>
  );
}
```

### Alert Dialog

Use `AlertDialog` for confirmation, error messages, and other critical information that must be acknowledged.

```tsx
import {AlertDialog, DialogTrigger, Button} from '@react-spectrum/s2';

function Example(props) {
  return (
    <DialogTrigger>
      <Button>Publish</Button>
      {/*- begin focus -*/}
      <AlertDialog
        {...props}
        
        onPrimaryAction={() => alert('onPrimaryAction')}
        onSecondaryAction={() => alert('onSecondaryAction')}>
        {props.children}
      </AlertDialog>
      {/*- end focus -*/}
    </DialogTrigger>
  );
}
```

### Fullscreen Dialog

Use `FullscreenDialog` for complex workflows that require more space. It supports `Heading`, `Header`, `Content`, and `ButtonGroup` slots.

```tsx
import {FullscreenDialog, DialogTrigger, Button, ButtonGroup, Heading, Header, Content} from '@react-spectrum/s2';

function Example(props) {
  return (
    <DialogTrigger>
      <Button variant="primary">Open Fullscreen</Button>
      {/*- begin focus -*/}
      <FullscreenDialog {...props}>
        {({close}) => (
          <>
            <Heading slot="title">Advanced Settings</Heading>
            <Header>Configure your application preferences</Header>
            <Content>
              <p>This fullscreen dialog provides ample space for complex forms, detailed content, or multi-step workflows.</p>
              <p>The content area can scroll if needed, making it perfect for lengthy forms or comprehensive settings panels.</p>
            </Content>
            <ButtonGroup>
              <Button onPress={close} variant="secondary">Cancel</Button>
              <Button onPress={close} variant="accent">Save Changes</Button>
            </ButtonGroup>
          </>
        )}
      </FullscreenDialog>
      {/*- end focus -*/}
    </DialogTrigger>
  );
}
```

### Custom Dialog

Use `CustomDialog` for complete control over the dialog layout.

```tsx
import {CustomDialog, DialogTrigger, Button, Heading, CloseButton} from '@react-spectrum/s2';
import Checkmark from '@react-spectrum/s2/illustrations/gradient/generic1/Checkmark';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};

function Example(props) {
  return (
    <DialogTrigger>
      <Button>Open dialog</Button>
      {/*- begin focus -*/}
      <CustomDialog {...props}>
        <div className={style({display: 'flex', flexDirection: 'column', rowGap: 8, alignItems: 'center'})}>
          <Checkmark />
          <Heading slot="title" styles={style({font: 'heading-lg', textAlign: 'center', marginY: 0})}>Thank you!</Heading>
          <p className={style({font: 'body', textAlign: 'center', marginY: 0})}>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
          <CloseButton styles={style({position: 'absolute', top: 12, insetEnd: 12})} />
        </div>
      </CustomDialog>
      {/*- end focus -*/}
    </DialogTrigger>
  );
}
```

## Dialog Container

Use `DialogContainer` to show a dialog programmatically or mount in a different part of the JSX tree (e.g. outside a menu).

```tsx
import {DialogContainer, Dialog, Button, ButtonGroup, Heading, Content, ActionMenu, MenuItem} from '@react-spectrum/s2';
import {useState} from 'react';

function DialogContainerExample() {
  let [dialogType, setDialogType] = useState(null);

  return (
    <>
      <ActionMenu onAction={setDialogType}>
        <MenuItem id="edit">Edit Item</MenuItem>
        <MenuItem id="delete">Delete Item</MenuItem>
        <MenuItem id="share">Share Item</MenuItem>
      </ActionMenu>
      
      {/*- begin highlight -*/}
      <DialogContainer onDismiss={() => setDialogType(null)}>
      {/*- end highlight -*/}
        {dialogType === 'edit' && (
          <Dialog>
            {({close}) => (
              <>
                <Heading slot="title">Edit Item</Heading>
                <Content>Make changes to your item here.</Content>
                <ButtonGroup>
                  <Button onPress={close} variant="secondary">Cancel</Button>
                  <Button onPress={close} variant="accent">Save</Button>
                </ButtonGroup>
              </>
            )}
          </Dialog>
        )}
        {dialogType === 'delete' && (
          <Dialog>
            {({close}) => (
              <>
                <Heading slot="title">Delete Item</Heading>
                <Content>Are you sure you want to delete this item? This action cannot be undone.</Content>
                <ButtonGroup>
                  <Button onPress={close} variant="secondary">Cancel</Button>
                  <Button onPress={close} variant="negative">Delete</Button>
                </ButtonGroup>
              </>
            )}
          </Dialog>
        )}
        {dialogType === 'share' && (
          <Dialog>
            {({close}) => (
              <>
                <Heading slot="title">Share Item</Heading>
                <Content>Choose how you would like to share this item.</Content>
                <ButtonGroup>
                  <Button onPress={close} variant="secondary">Cancel</Button>
                  <Button onPress={close} variant="accent">Share</Button>
                </ButtonGroup>
              </>
            )}
          </Dialog>
        )}
      </DialogContainer>
    </>
  );
}
```

## API

### Dialog

```tsx
<Dialog>
  <Image slot="hero">
  <Heading slot="title" />
  <Header />
  <Content />
  <Footer />
  <ButtonGroup />
</Dialog>
```

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `aria-describedby` | `string | undefined` | — | Identifies the element (or elements) that describes the object. |
| `aria-details` | `string | undefined` | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
| `aria-label` | `string | undefined` | — | Defines a string value that labels the current element. |
| `aria-labelledby` | `string | undefined` | — | Identifies the element (or elements) that labels the current element. |
| `children` | `ReactNode | ((opts: DialogRenderProps) => ReactNode)` | — | Children of the dialog. A function may be provided to access a function to close the dialog. |
| `id` | `string | undefined` | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
| `isDismissible` | `boolean | undefined` | — | Whether the Dialog is dismissible. |
| `isKeyboardDismissDisabled` | `boolean | undefined` | — | Whether pressing the escape key to close the dialog should be disabled. |
| `role` | `"alertdialog" | "dialog" | undefined` | 'dialog' | The accessibility role for the dialog. |
| `size` | `"S" | "M" | "L" | "XL" | undefined` | 'M' | The size of the Dialog. |
| `slot` | `string | null | undefined` | — | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit `null` value indicates that the local props completely override all props received from a parent. |
| `styles` | `StylesProp | undefined` | — | Spectrum-defined styles, returned by the `style()` macro. |
| `UNSAFE_className` | `UnsafeClassName | undefined` | — | Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |
| `UNSAFE_style` | `CSSProperties | undefined` | — | Sets inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |

### AlertDialog

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `autoFocusButton` | `"cancel" | "primary" | "secondary" | undefined` | — | Button to focus by default when the dialog opens. |
| `cancelLabel` | `string | undefined` | — | The label to display within the cancel button. |
| `children` | `ReactNode` | — | The contents of the AlertDialog. |
| `id` | `string | undefined` | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
| `isPrimaryActionDisabled` | `boolean | undefined` | — | Whether the primary button is disabled. |
| `isSecondaryActionDisabled` | `boolean | undefined` | — | Whether the secondary button is disabled. |
| `onCancel` | `(() => void) | undefined` | — | Handler that is called when the cancel button is pressed. |
| `onPrimaryAction` | `(() => void) | undefined` | — | Handler that is called when the primary button is pressed. |
| `onSecondaryAction` | `(() => void) | undefined` | — | Handler that is called when the secondary button is pressed. |
| `primaryActionLabel` | `string` | — | The label to display within the confirm button. |
| `secondaryActionLabel` | `string | undefined` | — | The label to display within the secondary button. |
| `size` | `"S" | "M" | "L" | undefined` | 'M' | The size of the Dialog. |
| `title` | `string` | — | The title of the AlertDialog. |
| `UNSAFE_className` | `UnsafeClassName | undefined` | — | Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |
| `UNSAFE_style` | `CSSProperties | undefined` | — | Sets inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |
| `variant` | `"error" | "confirmation" | "information" | "destructive" | "warning" | undefined` | — | The [visual style](https://spectrum.adobe.com/page/alert-dialog/#Options) of the AlertDialog. |

### FullscreenDialog

```tsx
<FullscreenDialog>
  <Heading slot="title" />
  <Header />
  <Content />
  <ButtonGroup />
</FullscreenDialog>
```

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `aria-describedby` | `string | undefined` | — | Identifies the element (or elements) that describes the object. |
| `aria-details` | `string | undefined` | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
| `aria-label` | `string | undefined` | — | Defines a string value that labels the current element. |
| `aria-labelledby` | `string | undefined` | — | Identifies the element (or elements) that labels the current element. |
| `children` | `ReactNode | ((opts: DialogRenderProps) => ReactNode)` | — | Children of the dialog. A function may be provided to access a function to close the dialog. |
| `id` | `string | undefined` | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
| `isKeyboardDismissDisabled` | `boolean | undefined` | — | Whether pressing the escape key to close the dialog should be disabled. |
| `role` | `"alertdialog" | "dialog" | undefined` | 'dialog' | The accessibility role for the dialog. |
| `slot` | `string | null | undefined` | — | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit `null` value indicates that the local props completely override all props received from a parent. |
| `styles` | `StylesProp | undefined` | — | Spectrum-defined styles, returned by the `style()` macro. |
| `UNSAFE_className` | `UnsafeClassName | undefined` | — | Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |
| `UNSAFE_style` | `CSSProperties | undefined` | — | Sets inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |
| `variant` | `"fullscreen" | "fullscreenTakeover" | undefined` | "fullscreen" | The variant of fullscreen dialog to display. |

### CustomDialog

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `aria-describedby` | `string | undefined` | — | Identifies the element (or elements) that describes the object. |
| `aria-details` | `string | undefined` | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
| `aria-label` | `string | undefined` | — | Defines a string value that labels the current element. |
| `aria-labelledby` | `string | undefined` | — | Identifies the element (or elements) that labels the current element. |
| `children` | `ReactNode | ((opts: DialogRenderProps) => ReactNode)` | — | Children of the dialog. A function may be provided to access a function to close the dialog. |
| `id` | `string | undefined` | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
| `isDismissible` | `boolean | undefined` | — | Whether the Dialog is dismissible. |
| `isKeyboardDismissDisabled` | `boolean | undefined` | — | Whether pressing the escape key to close the dialog should be disabled. |
| `padding` | `"none" | "default" | undefined` | 'default' | The amount of padding around the contents of the dialog. |
| `role` | `"alertdialog" | "dialog" | undefined` | 'dialog' | The accessibility role for the dialog. |
| `size` | `"S" | "M" | "L" | "fullscreen" | "fullscreenTakeover" | undefined` | — | The size of the Dialog. |
| `slot` | `string | null | undefined` | — | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit `null` value indicates that the local props completely override all props received from a parent. |
| `styles` | `StylesProp | undefined` | — | Spectrum-defined styles, returned by the `style()` macro. |
| `UNSAFE_className` | `UnsafeClassName | undefined` | — | Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |
| `UNSAFE_style` | `CSSProperties | undefined` | — | Sets inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. Only use as a **last resort**. Use the `style` macro via the `styles` prop instead. |

### DialogTrigger

```tsx
<DialogTrigger>
  <Button />
  <Dialog />
</DialogTrigger>
```

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `ReactNode` | — |  |
| `defaultOpen` | `boolean | undefined` | — | Whether the overlay is open by default (uncontrolled). |
| `isOpen` | `boolean | undefined` | — | Whether the overlay is open by default (controlled). |
| `onOpenChange` | `((isOpen: boolean) => void) | undefined` | — | Handler that is called when the overlay's open state changes. |

### DialogContainer

```tsx
<DialogContainer>
  <Dialog />
</DialogContainer>
```

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode` | — | The Dialog to display, if any. |
| `onDismiss` | `() => void` | — | Handler that is called when the 'x' button of a dismissable Dialog is clicked. |
