A ModalAlert is a simple modal dialog used to alert a user of an issue, or to request confirmation after a user-triggered action. ModalAlert overlays and blocks page content until it is dismissed by the user.

also known as AlertDialog, Prompt

Web:

iOS:

Android:

Props

Component props
Name
Type
Default
accessibilityModalLabel
Required
string
-

String that clients such as VoiceOver will read to describe the modal. Always localize the label. See Accessibility section for more info.

children
Required
React.Node
-

Supply the element(s) that will be used as ModalAlert's main content. See the Best Practices for more info.

heading
Required
string
-

The text used for ModalAlert's heading.

onDismiss
Required
() => void
-

Callback fired when ModalAlert is dismissed by clicking on the backdrop outside of the ModalAlert or when the dismiss icon button is clicked (for default ModalAlerts).

primaryAction
Required
{|
  accessibilityLabel: string,
  disabled?: boolean,
  href?: string,
  label: string,
  onClick?: ({|
    event:
      | SyntheticMouseEvent<HTMLButtonElement>
      | SyntheticMouseEvent<HTMLAnchorElement>
      | SyntheticKeyboardEvent<HTMLAnchorElement>
      | SyntheticKeyboardEvent<HTMLButtonElement>,
    dangerouslyDisableOnNavigation: () => void,
  |}) => void,
  rel?: "none" | "nofollow",
  target?: null | "self" | "blank",
|}
-

Main action for users to take on ModalAlert. If href is supplied, the action will serve as a link. See OnLinkNavigationProvider to learn more about link navigation.
If no href is supplied, the action will be a button.
The accessibilityLabel should follow the Accessibility guidelines.

accessibilityDismissButtonLabel
string
-

Label to describe the dismiss button's purpose.

secondaryAction
{|
  accessibilityLabel: string,
  disabled?: boolean,
  href?: string,
  label: string,
  onClick?: ({|
    event:
      | SyntheticMouseEvent<HTMLButtonElement>
      | SyntheticMouseEvent<HTMLAnchorElement>
      | SyntheticKeyboardEvent<HTMLAnchorElement>
      | SyntheticKeyboardEvent<HTMLButtonElement>,
    dangerouslyDisableOnNavigation: () => void,
  |}) => void,
  rel?: "none" | "nofollow",
  target?: null | "self" | "blank",
|}
-

Secondary action for users to take on ModalAlert. If href is supplied, the action will serve as a link. See OnLinkNavigationProvider to learn more about link navigation.
If no href is supplied, the action will be a button.
The accessibilityLabel should follow the Accessibility guidelines.

type
"default" | "warning" | "error"
-

Determines the icon and dismiss pattern of the ModalAlert. See the warning and error variants for more info.

Usage guidelines

When to use
  • Interrupting users to get confirmation on a user-triggered action that is potentially disruptive or significantly changes the user’s content and system.
  • Interrupting users to alert them of potential issues and errors; this can be user or system-generated.
When not to use
  • Requesting large forms of information. Consider Sheet or new page instead.
  • Any action that should not interrupt users from their current work stream, such as saving a Pin. Use Toast instead.
  • When alerting users of issues that can be corrected on the page or surface itself without interrupting their flow. Instead use Callout or SlimBanner.

Best practices

Do

Clearly communicate what response is expected and make the action simple and straightforward, such as clicking/tapping a button to confirm.

Do

Limit the content to prevent the need to scroll at most screen sizes.

Do

Provide a way for the user to correct an error or issue via a button or a link.

Do

Explain to the user why they’ve encountered a warning or error when an action button or link is not possible.

Don't

Use language that makes it hard to understand what action is being taken, while adding additional actions that may take the user out of their existing context.

Don't

Use ModalAlert on top of another modal dialog. This can cause accessibility issues with focus states and make it hard for a user to escape and go back to the previous surface. On mobile surfaces, if a user has to confirm something triggered by a modal dialog, auto-dismiss the first dialog before presenting with the confirmation dialog.

Don't

Use ModalAlert for long and complex content or tasks, or for content that should have a dedicated surface, like login flows. If extra functionality is needed in an overlay, use Modal or Sheet.

Don't

Leave it up to the user to find where to go to fix an issue.

Don't

Omit an explanation as to why a user is encountering an error or issue.

Accessibility

Labels

Make sure ModalAlerts have a clear purpose when being read by a screen reader by specifying an accessibilityModalLabel that will update the spoken text for the heading prop and give the user more context about the ModalAlert. Also ensure the accessibilityLabel is supplied when primaryAction or secondaryAction is specified. This label should provide a clear description of the action's purpose, like "Cancel board deletion".

Localization

Be sure to localize the heading and accessibilityModalLabelprops, as well as any other text elements within ModalAlert. Note that localization can lengthen text by 20 to 30 percent.

Variants

Multiple actions for confirmation

This is generally triggered by user action and asks a user to confirm or cancel an action. Confirmation ModalAlerts should always have a primary and secondary button; the primary button is for confirming, and the secondary for dismissing the modal. Confirmations aren’t critical and can be dismissed by clicking outside of the modal and hitting the ESC key, in addition to using the “Cancel” buttons provided in the modal.

import { ModalAlert, CompositeZIndex, FixedZIndex, Layer, Text } from 'gestalt';

const HEADER_ZINDEX = new FixedZIndex(10);
const zIndex = new CompositeZIndex([HEADER_ZINDEX]);

export default function MultipleActions() {
  return (
    <Layer zIndex={zIndex}>
      <ModalAlert
        accessibilityModalLabel="Delete current Pin draft confirmation"
        heading="Delete this draft?"
        primaryAction={{
          accessibilityLabel: 'Delete draft',
          label: 'Delete',
          onClick: () => {},
        }}
        secondaryAction={{
          accessibilityLabel: 'Cancel, keep editing',
          label: 'Return to editing',
          onClick: () => {},
        }}
        onDismiss={() => {}}
      >
        <Text>
          Deleting this draft cannot be undone. Are you sure you want to delete?
        </Text>
      </ModalAlert>
    </Layer>
  );
}

Single action for acknowledgment

This is system-generated and only requires a user to dismiss the message.

import { ModalAlert, CompositeZIndex, FixedZIndex, Layer, Text } from 'gestalt';

const HEADER_ZINDEX = new FixedZIndex(10);
const zIndex = new CompositeZIndex([HEADER_ZINDEX]);

export default function WarningSingleAction() {
  return (
    <Layer zIndex={zIndex}>
      <ModalAlert
        type="warning"
        accessibilityModalLabel="Unable to follow more people"
        heading="Follower limit reached"
        primaryAction={{
          accessibilityLabel: '',
          label: 'Got it',
          onClick: () => {},
        }}
        onDismiss={() => {}}
      >
        <Text>
          You&apos;ve hit a spam block and can&apos;t follow any more people
          right now. Try again later.
        </Text>
      </ModalAlert>
    </Layer>
  );
}

Warning type

Warnings are used to alert a user that they need to proceed with caution. Due to their critical nature, warnings can only be dismissed by interacting with the dismiss buttons provided by the modal. If there is a way to resolve the warning, two buttons can be included. If not, only one “dismiss” button is needed.

import { ModalAlert, CompositeZIndex, FixedZIndex, Layer, Text } from 'gestalt';

const HEADER_ZINDEX = new FixedZIndex(10);
const zIndex = new CompositeZIndex([HEADER_ZINDEX]);

export default function WarningMultiAction() {
  return (
    <Layer zIndex={zIndex}>
      <ModalAlert
        type="warning"
        accessibilityModalLabel="Spam link warning"
        heading="This site may lead to spam"
        primaryAction={{
          accessibilityLabel: 'Continue to Pin site',
          label: 'Continue to site',
          href: 'https://www.google.com',
        }}
        secondaryAction={{
          accessibilityLabel: 'Cancel navigation to site',
          label: 'Cancel',
          onClick: () => {},
        }}
        onDismiss={() => {}}
      >
        <Text>
          We aren&apos;t sure of the contents of this site and can&apos;t verify
          that you will find what you are looking for. Are you sure you want to
          continue?
        </Text>
      </ModalAlert>
    </Layer>
  );
}
import { ModalAlert, CompositeZIndex, FixedZIndex, Layer, Text } from 'gestalt';

const HEADER_ZINDEX = new FixedZIndex(10);
const zIndex = new CompositeZIndex([HEADER_ZINDEX]);

export default function WarningSingleAction() {
  return (
    <Layer zIndex={zIndex}>
      <ModalAlert
        type="warning"
        accessibilityModalLabel="Unable to follow more people"
        heading="Follower limit reached"
        primaryAction={{
          accessibilityLabel: '',
          label: 'Got it',
          onClick: () => {},
        }}
        onDismiss={() => {}}
      >
        <Text>
          You&apos;ve hit a spam block and can&apos;t follow any more people
          right now. Try again later.
        </Text>
      </ModalAlert>
    </Layer>
  );
}

Error type

Error messages alert users of an error or a very critical issue that severely limits the user’s ability to continue. Like warnings, errors can only be dismissed by interacting with the dismiss buttons provided by the modal. If there is a way to resolve the error, two buttons can be included. If not, only one “dismiss” button is needed.

import { ModalAlert, CompositeZIndex, FixedZIndex, Layer, Text } from 'gestalt';

const HEADER_ZINDEX = new FixedZIndex(10);
const zIndex = new CompositeZIndex([HEADER_ZINDEX]);

export default function ErrorMultiAction() {
  return (
    <Layer zIndex={zIndex}>
      <ModalAlert
        type="error"
        accessibilityModalLabel="API access revoked error"
        heading="Your API access has been revoked"
        primaryAction={{
          accessibilityLabel: 'Submit appeal to Pinterest',
          label: 'Submit an appeal',
          href: 'https://www.pinterest.com',
        }}
        secondaryAction={{
          accessibilityLabel: 'Cancel',
          label: 'Cancel',
          onClick: () => {},
        }}
        onDismiss={() => {}}
      >
        <Text>
          You will not be able to make any API calls or create new apps.
          Pinterest Developers functionality will be limited to read-only data
          until you submit an appeal.
        </Text>
      </ModalAlert>
    </Layer>
  );
}
import {
  ModalAlert,
  CompositeZIndex,
  FixedZIndex,
  Layer,
  Link,
  Text,
} from 'gestalt';

const HEADER_ZINDEX = new FixedZIndex(10);
const zIndex = new CompositeZIndex([HEADER_ZINDEX]);

export default function ErrorSingleAction() {
  return (
    <Layer zIndex={zIndex}>
      <ModalAlert
        type="error"
        accessibilityModalLabel="Site blocked error"
        heading="Website blocked"
        primaryAction={{
          accessibilityLabel: 'Acknowledge site blocked',
          label: 'Got it',
          onClick: () => {},
        }}
        onDismiss={() => {}}
      >
        <Text>
          We blocked the website you are trying to reach because it contains
          harmful material. Review our{' '}
          <Link
            underline="always"
            inline
            href="https://policy.pinterest.com/en/community-guidelines"
          >
            content policy.
          </Link>
        </Text>
      </ModalAlert>
    </Layer>
  );
}

With checkbox

Checkbox can be added to a modal that isn’t a warning or an error. Checkboxes are normally used for confirmation modals that may appear frequently in a creation or editing flow. An example is creating an Idea Pin. If the action is infrequent or highly destructive (like deleting something), do not offer an option to not show the modal again.

import { useState } from 'react';
import {
  ModalAlert,
  Checkbox,
  CompositeZIndex,
  FixedZIndex,
  Flex,
  Layer,
  Text,
} from 'gestalt';

const HEADER_ZINDEX = new FixedZIndex(10);
const zIndex = new CompositeZIndex([HEADER_ZINDEX]);

export default function WithCheckbox() {
  const [checked1, setChecked1] = useState(false);

  return (
    <Layer zIndex={zIndex}>
      <ModalAlert
        accessibilityModalLabel="Delete current Pin draft confirmation"
        heading="Delete this page?"
        primaryAction={{
          accessibilityLabel: 'Delete page',
          label: 'Delete page',
          onClick: () => {},
        }}
        secondaryAction={{
          accessibilityLabel: 'Cancel, keep page',
          label: 'Cancel',
          onClick: () => {},
        }}
        onDismiss={() => {}}
      >
        <Flex direction="column" gap={4} flex="grow">
          <Text>
            If you change your mind, you&apos;ll have to create this pin
            again—starting from the very beginning.
          </Text>
          <Checkbox
            checked={checked1}
            id="checkbox-show-again"
            label="Got it—don't warn me again"
            onChange={({ checked }) => setChecked1(checked)}
          />
        </Flex>
      </ModalAlert>
    </Layer>
  );
}

Writing

Do
  • Consider internationalization and how other languages may be constrained.
  • Use concise language while making it clear what is expected of the user. If the desired action can be confused with “Cancel”, add “Yes,” to the action. For example “Yes, remove”, “No, keep”
Don't
  • Pose a question in the headline that isn’t clear about the action being proposed, like “Are you sure?”
  • Use lengthy, technical jargon or local idioms that will be hard to translate to other languages.
  • Avoid exclamation marks unless the tone is celebratory; this is especially true when surfacing errors or warnings.

Component quality checklist

Component quality checklist
Quality item
Status
Status description
Figma Library
Partially ready
Component is live in Figma, however may not be available for all platforms.
Responsive Web
Ready
Component is available in code for web and mobile web.
iOS
Component is not currently available in code for iOS.
Android
Component is not currently available in code for Android.

Toast
Toast provides feedback shortly after a user interaction, like a confirmation that appears when a Pin has been saved. Unlike Upsells and SlimBanners, toasts overlay Page content. They also automatically disappear after a certain amount of time without being dismissed by the user.

Callout
Callouts are used at the top-most level of a page to communicate highest-priority information that applies to the entire page or surface. Callouts can be dismissed and are also actionable.

SlimBanner
SlimBanner conveys brief information related to a specific section of a page. The message can relay success, warning, error or general information.

Modal
A generic, customizable container for modals that aren’t used as alerts and need more functionality, like form fields.