{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:react-aria-components';
import overlayStatelyDocs from 'docs:@react-stately/overlays';
import {PropTable, HeaderInfo, TypeLink, PageDescription, StateTable, ContextTable, VersionBadge, ClassAPI} from '@react-spectrum/docs';
import styles from '@react-spectrum/docs/src/docs.css';
import packageData from 'react-aria-components/package.json';
import Anatomy from '/packages/react-aria/docs/dialog/anatomy.svg';
import ChevronRight from '@spectrum-icons/workflow/ChevronRight';
import {Divider} from '@react-spectrum/divider';
import {ExampleCard} from '@react-spectrum/docs/src/ExampleCard';
import {ExampleList} from '@react-spectrum/docs/src/ExampleList';
import {Keyboard} from '@react-spectrum/text';
import {StarterKits} from '@react-spectrum/docs/src/StarterKits';

---
category: Overlays
keywords: [dialog, popover, aria]
type: component
---

# Dialog

<PageDescription>{docs.exports.Dialog.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Dialog']}
  sourceData={[
    {type: 'W3C', url: 'https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/'}
  ]} />

## Example

```tsx example
import {DialogTrigger, Modal, Dialog, Button, Heading, TextField, Label, Input} from 'react-aria-components';

<DialogTrigger>
  <Button>Sign up…</Button>
  <Modal>
    <Dialog>
      <form>
        <Heading slot="title">Sign up</Heading>
        <TextField autoFocus>
          <Label>First Name</Label>
          <Input />
        </TextField>
        <TextField>
          <Label>Last Name</Label>
          <Input />
        </TextField>
        <Button slot="close" style={{marginTop: 8}}>
          Submit
        </Button>
      </form>
    </Dialog>
  </Modal>
</DialogTrigger>
```

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>
```css hidden
@import "@react-aria/example-theme";
@import './Button.mdx' layer(button);
@import './TextField.mdx' layer(textfield);
@import './Popover.mdx' layer(popover);
@import './Modal.mdx' layer(modal);
```

```css
.react-aria-Dialog {
  outline: none;
  padding: 30px;
  max-height: inherit;
  box-sizing: border-box;
  overflow: auto;

  .react-aria-Heading[slot=title] {
    line-height: 1em;
    margin-top: 0;
  }
}
```

</details>

## Features

The HTML [&lt;dialog&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) element
can be used to build dialogs. However, it is not yet widely supported across browsers, and
building fully accessible custom dialogs from scratch is very difficult and error prone.
`Dialog` helps achieve accessible dialogs that can be styled as needed.

* **Flexible** – Dialogs can be used within a [Modal](Modal.html) or [Popover](Popover.html) to create many types of overlay elements.
* **Accessible** – Exposed to assistive technology as a `dialog` or `alertdialog` with ARIA. The dialog is automatically labeled by a nested `<Heading>` element. Content outside the dialog is hidden from assistive technologies while it is open.
* **Focus management** – Focus is moved into the dialog on mount, and restored to the trigger element on unmount. While open, focus is contained within the dialog, preventing the user from tabbing outside.

## Anatomy

<Anatomy />

A dialog consists of a container element and an optional title and close button. It can be placed within a [Modal](Modal.html) or [Popover](Popover.html), to create modal dialogs, popovers, and other types of overlays. A `DialogTrigger` can be used to open a dialog overlay in response to a user action, e.g. clicking a button.

```tsx
import {DialogTrigger, Modal, Dialog, Button, Heading} from 'react-aria-components';

<DialogTrigger>
  <Button />
  <Modal>
    <Dialog>
      <Heading slot="title" />
      <Button slot="close" />
    </Dialog>
  </Modal>
</DialogTrigger>
```

If a dialog does not have a visible heading element, an `aria-label` or `aria-labelledby` prop must be passed instead to identify the element to assistive technology.

## Examples

<ExampleList tag="dialog" />

## Starter kits

To help kick-start your project, we offer starter kits that include example implementations of all React Aria components with various styling solutions. All components are fully styled, including support for dark mode, high contrast mode, and all UI states. Each starter comes with a pre-configured [Storybook](https://storybook.js.org/) that you can experiment with, or use as a starting point for your own component library.

<StarterKits component="dialog" tailwindComponent="alertdialog" />

## Popover

A `Dialog` may be placed within a [Popover](Popover.html) to display it in context with a trigger element.

```tsx example
import {Popover, OverlayArrow} from 'react-aria-components';

<DialogTrigger>
  <Button aria-label="Help">ⓘ</Button>
  <Popover>
    <OverlayArrow>
      <svg width={12} height={12} viewBox="0 0 12 12"><path d="M0 0 L6 6 L12 0" /></svg>
    </OverlayArrow>
    <Dialog>
      <Heading slot="title">Help</Heading>
      <p>For help accessing your account, please contact support.</p>
    </Dialog>
  </Popover>
</DialogTrigger>
```

## Alert dialog

Alert dialogs are a special type of dialog meant to present a prompt that the user must confirm before an action proceeds. An alert dialog may also behave differently with assistive technologies, such as playing a system alert sound when opening. Use the `role="alertdialog"` prop on the `<Dialog>` element to make an alert dialog.

```tsx example
<DialogTrigger>
  <Button>Delete…</Button>
  <Modal>
    <Dialog role="alertdialog">
      {({close}) => (
        <>
          <Heading slot="title">Delete file</Heading>
          <p>This will permanently delete the selected file. Continue?</p>
          <div style={{display: 'flex', gap: 8}}>
            <Button onPress={close}>Cancel</Button>
            <Button onPress={close}>Delete</Button>
          </div>
        </>
      )}
    </Dialog>
  </Modal>
</DialogTrigger>
```

## Custom trigger

`DialogTrigger` works out of the box with any pressable React Aria component (e.g. [Button](Button.html), [Link](Link.html), etc.). Custom trigger elements such as third party components and other DOM elements are also supported by wrapping them with the `<Pressable>` component, or using the [usePress](usePress.html) hook.

```tsx example
import {Pressable} from 'react-aria-components';

<DialogTrigger>
  {/*- begin highlight -*/}
  <Pressable>
    <span role="button">Custom trigger</span>
  </Pressable>
  {/*- end highlight -*/}
  <Modal>
    <Dialog>
      <Heading slot="title">Dialog</Heading>
      <p>This dialog was triggered by a custom button.</p>
      <Button slot="close">Close</Button>
    </Dialog>
  </Modal>
</DialogTrigger>
```

Note that any `<Pressable>` child must have an [interactive ARIA role](https://www.w3.org/TR/wai-aria-1.2/#widget_roles) or use an appropriate semantic HTML element so that screen readers can announce the trigger. Trigger components must forward their `ref` and spread all props to a DOM element.

```tsx
const CustomTrigger = React.forwardRef((props, ref) => (
  <button {...props} ref={ref} />
));
```

## Props

### DialogTrigger

<PropTable component={docs.exports.DialogTrigger} links={docs.links} />

### Dialog

<PropTable component={docs.exports.Dialog} links={docs.links} />

### Heading

A `<Heading>` accepts all HTML attributes.

### Button

A `<Button slot="close">` element can be placed inside a `<Dialog>` to close it when pressed.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show props</summary>

<PropTable component={docs.exports.Button} links={docs.links} />

</details>

## Styling

React Aria components can be styled in many ways, including using CSS classes, inline styles, utility classes (e.g. Tailwind), CSS-in-JS (e.g. Styled Components), etc. By default, all components include a builtin `className` attribute which can be targeted using CSS selectors. These follow the `react-aria-ComponentName` naming convention.

```css
.react-aria-Dialog {
  /* ... */
}
```

A custom `className` can also be specified on any component. This overrides the default `className` provided by React Aria with your own.

```jsx
<Dialog className="my-dialog">
  {/* ... */}
</Dialog>
```

The selectors for each component used in a `Dialog` are documented below.

### DialogTrigger

The `DialogTrigger` component does not render any DOM elements (it only passes through its children) so it does not support styling. If you need a wrapper element, add one yourself inside the `<DialogTrigger>`.

```jsx
<DialogTrigger>
  <div className="my-dialog-trigger">
    {/* ... */}
  </div>
</DialogTrigger>
```

### Dialog

A `Dialog` can be targeted with the `.react-aria-Dialog` CSS selector, or by overriding with a custom `className`.

### Heading

A `Heading` can be targeted with the `.react-aria-Heading` CSS selector, or by overriding with a custom `className`.

## Advanced customization

### Custom children

DialogTrigger and Dialog pass props to their child components, such as the trigger button and modal overlay, via their associated contexts. These contexts are exported so you can also consume them in your own custom components. This enables you to reuse existing components from your app or component library together with React Aria Components.

<ContextTable components={['Button', 'Dialog', 'Modal', 'Popover', 'Heading']} docs={docs} />

This example consumes from `HeadingContext` in an existing styled heading component to make it compatible with React Aria Components. The <TypeLink links={docs.links} type={docs.exports.useContextProps} /> hook merges the local props and ref with the ones provided via context by Dialog.

```tsx
import type {HeadingProps} from 'react-aria-components';
import {HeadingContext, useContextProps} from 'react-aria-components';

const MyCustomHeading = React.forwardRef((props: HeadingProps, ref: React.ForwardedRef<HTMLHeadingElement>) => {
  // Merge the local props and ref with the ones provided via context.
  ///- begin highlight -///
  [props, ref] = useContextProps(props, ref, HeadingContext);
  ///- end highlight -///

  // ... your existing Heading component
  return <h2 {...props} ref={ref} />;
});
```

Now you can use `MyCustomHeading` within a `Dialog`, in place of the builtin React Aria Components `Heading`.

```tsx
<Dialog>
  {/*- begin highlight -*/}
  <MyCustomHeading>Dialog title</MyCustomHeading>
  {/*- end highlight -*/}
  {/* ... */}
</Dialog>
```

### State

DialogTrigger provides an <TypeLink links={overlayStatelyDocs.links} type={overlayStatelyDocs.exports.OverlayTriggerState} /> object to its children via `OverlayTriggerStateContext`. This can be used to access and manipulate the dialog trigger's state.

This example shows a `CloseButton` component that can be placed within a `DialogTrigger` to close the overlay.

```tsx example
import {OverlayTriggerStateContext} from 'react-aria-components';

function CloseButton() {
  /*- begin highlight -*/
  let state = React.useContext(OverlayTriggerStateContext)!;
  /*- end highlight -*/
  return <Button onPress={() => state.close()}>Close</Button>;
}

<DialogTrigger>
  <Button>About</Button>
  <Modal isDismissable>
    <Dialog>
      <Heading slot="title">About</Heading>
      <p>Copyright © 2023 Adobe. All rights reserved.</p>
      {/*- begin highlight -*/}
      <CloseButton />
      {/*- end highlight -*/}
    </Dialog>
  </Modal>
</DialogTrigger>
```

### Hooks

If you need to customize things further, such as accessing internal state or customizing DOM structure, you can drop down to the lower level Hook-based API. See [useDialog](useDialog.html) for more details.
