Skip to content

AlertDialog

AlertDialog - AlertDialogContent - AlertDialogDescription - AlertDialogOverlay - AlertDialogContent

A modal dialog that interrupts the user's workflow to get a response, usually some sort of confirmation. This is different than a typical Dialog in that it requires some user response, like "Save", or "Cancel", etc.

Most of the time you'll use AlertDialog, AlertDialogLabel, and AlertDialogDescription together. If you need more control over the styling of the modal you can drop down a level and use AlertDialogOverlay and AlertDialogContent instead of AlertDialog.

When a Dialog opens, the least destructive action should be focused so that if a user accidentally hits enter when the dialog opens no damage is done. This is accomplished with the leastDestructiveRef prop.

Every dialog must render an AlertDialogLabel so the screen reader knows what to say about the dialog. If an AlertDialogDescription is also rendered, the screen reader will also announce that. If you render more than these two elements and some buttons, the screen reader might not announce it so it's important to keep the content inside of AlertDialogLabel and AlertDialogDescription.

This is built on top of Dialog, so AlertDialog spreds its props and renders a Dialog, same for AlertDialogOverlay to DialogOverlay, and AlertDialogContent to DialogContent.

() => {
  class App extends React.Component {

    constructor() {
      super()
      this.cancelRef = React.createRef();
      this.state = { showDialog: false };
      this.open = () => this.setState({ showDialog: true });
      this.close = () => this.setState({ showDialog: false });
    }

    render() {
      return (
        <div>
          <button onClick={this.open}>
            Delete something
          </button>

          {this.state.showDialog && (
            <AlertDialog leastDestructiveRef={this.cancelRef}>
              <AlertDialogLabel>Please Confirm!</AlertDialogLabel>

              <AlertDialogDescription>
                Are you sure you want to delete something? This action
                is permanent, and we're totally not just flipping a
                field called "deleted" to "true" in our database, we're
                actually deleting something.
              </AlertDialogDescription>

              <div className="alert-buttons">
                <button onClick={this.close}> 
                  Yes, delete
                </button>{" "}
                <button ref={this.cancelRef} onClick={this.close}> 
                  Nevermind, don't delete.
                </button>
              </div>
            </AlertDialog>
          )}
        </div>
      );
    }
  }

  return <App />;
}

Installation

npm install @reach/alert-dialog
# or
yarn add @reach/alert-dialog

And then import the components you need:

import {
  AlertDialog,
  AlertDialogLabel,
  AlertDialogDescription,
  AlertDialogOverlay,
  AlertDialogContent
} from "@reach/alert-dialog";

AlertDialog

High-level component to render an alert dialog.

<AlertDialog leastDestructiveRef={someRef}>
  <AlertDialogLabel/>
  <AlertDialogContent/>
</AlertDialog>

AlertDialog Props

PropType
Dialog propsspread
isOpenbool
onDismissfunc
leastDestructiveReffunc
childrennode

AlertDialog Dialog props

Type: spread

Any props not listed above will be spread onto the underlying Dialog element, which in turn is spread onto the underlying div[data-reach-dialog-content].

<AlertDialog style={{ color: "red" }}>
  <AlertDialogLabel>
    My text is red because the style prop got
    applied to the div underneath
  </AlertDialogLabel>
</AlertDialog>

AlertDialog isOpen

Type: bool default: true

Controls whether the dialog is open or not.

<AlertDialog isOpen={true}>
  <AlertDialogLabel>I will be open</AlertDialogLabel>
</AlertDialog>

<AlertDialog isOpen={false}>
  <AlertDialogLabel>I will be closed</AlertDialogLabel>
</AlertDialog>

Note, however, that the dialog will not render to the DOM when isOpen={false}, but you may want to save on the number of elements created in your render function. If you'd rather not have the dialog always rendered, you can put a guard in front of it and only render when it should be open. In this case you don’t need the isOpen prop at all.

{state.confirmDelete && (
  <AlertDialog isOpen={true}>
    <AlertDialogLabel>I will be open</AlertDialogLabel>
  </AlertDialog>
)}

You should probably do this when your dialog contains a lot of elements. It's also useful for transition animations.

AlertDialog onDismiss

Type: func

When the user clicks outside the modal or hits the escape key, this function will be called. If you want the modal to close, you’ll need to set state.

IMPORTANT: Ensure that onDismiss and the click handler of the leastDestructiveRef are identical!

() => {
  class App extends React.Component {
    constructor() {
      super();
      this.cancelRef = React.createRef();
      this.state = { confirmDelete: false };
      this.open = () =>
        this.setState({ confirmDelete: true });
      this.destroyStuff = () => {
        console.log("destroyed!");
        this.setState({ confirmDelete: false });
      };
      // make sure `onDismiss` and the `onClick` of the
      // `leastDestructiveRef` are identical, best to just
      // pass them both the same function
      this.onDismiss = () =>
        this.setState({ confirmDelete: false });
    }

    render() {
      return (
        <div>
          <button onClick={this.open}>
            Delete something
          </button>

          {this.state.confirmDelete && (
            <AlertDialog
              onDismiss={this.onDismiss}
              leastDestructiveRef={this.cancelRef}
            >
              <AlertDialogLabel>
                Please Confirm!
              </AlertDialogLabel>

              <AlertDialogDescription>
                Are you sure you want to delete something?
                This action is permanent, and we're totally
                not just flipping a field called "deleted"
                to "true" in our database, we're actually
                deleting something.
              </AlertDialogDescription>

              <div className="alert-buttons">
                <button onClick={this.destroyStuff}>
                  Yes, delete
                </button>{" "}
                <button
                  ref={this.cancelRef}
                  onClick={this.onDismiss}
                >
                  Nevermind, don't delete.
                </button>
              </div>
            </AlertDialog>
          )}
        </div>
      );
    }
  }

  return <App />;
};

AlertDialog leastDestructiveRef

Type: node

To prevent accidental data loss, an alert dialog should focus the least destructive action button when it opens.

() => {
  class App extends React.Component {
    constructor() {
      super();
      // we'll pass this ref to both AlertDialog and our button
      this.cancelRef = React.createRef();
      this.state = { confirm: false };
      this.open = () => this.setState({ confirm: true });
      this.publish = () => this.setState({ confirm: false })
      this.onDismiss = () =>
        this.setState({ confirm: false });
    }

    render() {
      return (
        <div>
          <button onClick={this.open}>
            Publish something
          </button>

          {this.state.confirm && (
            <AlertDialog
              leastDestructiveRef={this.cancelRef}
            >
              <AlertDialogLabel>
                Please Confirm!
              </AlertDialogLabel>

              <AlertDialogDescription>
                Are you sure you want to publish this thing?
              </AlertDialogDescription>

              <div className="alert-buttons">
                <button onClick={this.publish}>
                  Yes, publish and keep editing
                </button>{" "}
                <button onClick={this.publish}>
                  Yes, publish and view
                </button>{" "}
                <button
                  ref={this.cancelRef}
                  onClick={this.onDismiss}
                >
                  Don't publish, keep working
                </button>
              </div>
            </AlertDialog>
          )}
        </div>
      );
    }
  }

  return <App />;
};

AlertDialog children

Type: node

Accepts any renderable content but should generally be restricted to AlertDialogLabel, AlertDialogDescription and action buttons, other content might not be announced to the user by the screen reader.

<AlertDialog>
  <AlertDialogLabel>
    Please Confirm!
  </AlertDialog>

  <AlertDialogDescription>
    A longer message
  </AlertDialogDescription>

  <div>
    <button onClick={this.destroyStuff}>
      A Destructive Action
    </button>{" "}
    <button ref={leastDestructiveRef}>
      Least Destructive Action
    </button>
  </div>
</AlertDialog>

AlertDialogLabel

The first thing ready by screen readers when the dialog opens, usually the title of the dialog like "Warning!" or "Please confirm!".

This is required, the AlertDialog will throw an error if no label is rendered.

AlertDialogLabel CSS Selectors

Please see the styling guide.

Use the following CSS to target the label:

[data-reach-alert-dialog-label] {
  color: red;
}

AlertDialogLabel Props

PropType
element propsspread

AlertDialogLabel element props

Type: spread

All props are spread to an underlying div.

<AlertDialogLabel className="alert-label"/>

AlertDialogDescription

Additional content read by screen readers, usually a longer description about what you need from the user like "This action is permanent, are you sure?" etc.

AlertDialogDescription CSS Selectors

Please see the styling guide.

Use the following CSS to target the description:

[data-reach-alert-dialog-description] {
  text-align: center;
}

AlertDialogDescription Props

PropType
element propsspread

AlertDialogDescription element props

Type: spread

All props are spread to an underlying div.

<AlertDialogDescription className="alert-description"/>

AlertDialogOverlay

Low-level component if you need more control over the styles or rendering of the dialog overlay. In the following example we use the AlertDialogOverlay and AlertDialogContent to have more control over the styles.

Note: You must render an AlertDialogContent inside.

() => {
  class App extends React.Component {
    constructor() {
      super();
      // you'll pass this ref to both AlertDialog and your button
      this.cancelRef = React.createRef();
      this.state = { confirm: false };
      this.open = () => this.setState({ confirm: true });
      this.close = () => this.setState({ confirm: false });
    }

    render() {
      return (
        <div>
          <button onClick={this.open}>
            Delete something
          </button>

          {this.state.confirm && (
            <AlertDialogOverlay
              style={{ background: "hsla(0, 50%, 50%, 0.85)" }}
              leastDestructiveRef={this.cancelRef}
            >
              <AlertDialogContent style={{ background: '#f0f0f0' }}>
                <AlertDialogLabel>
                  Please Confirm!
                </AlertDialogLabel>

                <AlertDialogDescription>
                  Are you sure you want delete stuff,
                  it will be permanent.
                </AlertDialogDescription>

                <div className="alert-buttons">
                  <button onClick={this.close}>
                    Yes, delete
                  </button>{" "}
                  <button
                    ref={this.cancelRef}
                    onClick={this.close}
                  >
                    Nevermind
                  </button>
                </div>
              </AlertDialogContent>
            </AlertDialogOverlay>
          )}
        </div>
      );
    }
  }

  return <App />;
};

AlertDialogOverlay CSS Selectors

Please see the styling guide.

Use the following CSS to target the overlay:

[data-reach-alert-dialog-overlay] {
  background: hsla(0, 0%, 0%, 0.2);
}

AlertDialogOverlay Props

PropType
DialogOverlay propsspread
isOpenbool
onDismissfunc
leastDestructiveRefref
childrennode

AlertDialogOverlay element props

Type: spread

Any props not listed above will be spread onto the underlying DialogOverlay, and in turn spread onto the underlying div.

<AlertDialogOverlay className="light-modal"/>

AlertDialogOverlay isOpen

Type: bool

Same as AlertDialog isOpen

AlertDialogOverlay onDismiss

Type: func

Same as AlertDialog onDismiss

AlertDialogOverlay leastDestructiveRef

Type: ref

Same as AlertDialog leastDestructiveRef

AlertDialogOverlay children

Type: node

Should be an AlertDialogContent.

<AlertDialogOverlay>
  <AlertDialogContent/>
</AlertDialogOverlay>

AlertDialogContent

Low-level component if you need more control over the styles or rendering of the dialog content.

Note: Must be a child of AlertDialogOverlay.

Note: You only need to use this when you are also styling AlertDialogOverlay, otherwise you can use the high-level AlertDialog component and pass the props to it.

<AlertDialogOverlay style={someSpecificStyles}>
  <AlertDialogContent className={orAClassName}/>
</AlertDialogOverlay>

AlertDialogContent CSS Selectors

Please see the styling guide.

Use the following CSS to target the content:

[data-reach-alert-dialog-content] {
  border: solid 5px hsla(0, 0%, 0%, 0.5);
}

AlertDialogContent Props

PropType
DialogContent propsspread
childrennode

AlertDialogContent DialogContent props

Type: spread

Any props not listed above will be spread onto the underlying DialogContent element, and then again onto the underlying div.

<AlertDialogContent className="nice-border"/>

AlertDialogContent children

Type: node

Same as AlertDialog children