BannerOverlays displays short educational messages when users have performed actions that indicate some intent, such as a related pin tap or idea pin swipe. It is scrim-less, meaning users can scroll content underneath without having a wash layer on top of the content.

BannerOverlay is a sticky component triggered by scroll, on tap or long-press, placed at the bottom of the screen.

also known as UpsellOverlay

Figma:

Responsive:

Adaptive:

Props

Component props
Name
Type
Default
message
Required
string | ReactElement
-

Main content of BannerOverlay. Content should be localized. See the Text variant to learn more.

offset
{
  bottom: number;
  top: number;
  reverseOffset?: boolean;
}
"{ top: 0, bottom: 0, reverseOffset: false }"

Distance (in pixels) from the viewport edge (top will be used, if desktop, bottom will be used, if mobile). See the Responsive section to learn more.

onDismiss
() => void
-

Adds a dismiss button to BannerOverlay. See the Dismissible variant for more info.

primaryAction
{
    accessibilityLabel: string;
    href: string;
    label: string;
    onClick?: ComponentProps<typeof ButtonLink>["onClick"];
    rel?: ComponentProps<typeof ButtonLink>["rel"];
    role: "link";
    size?: ComponentProps<typeof ButtonLink>["size"];
    target?: ComponentProps<typeof ButtonLink>["target"];
  }
| {
    accessibilityLabel: string;
    label: string;
    onClick: ComponentProps<typeof Button>["onClick"];
    role?: "button";
    size?: ComponentProps<typeof Button>["size"];
  }
-

Adds an optional primary button for user interaction.
Main action for users to take on BannerOverlay. If href is supplied, the action will serve as a link.
If no href is supplied, the action will be a button.
The accessibilityLabel should follow the Accessibility guidelines.
See the Primary action variant to learn more.

secondaryAction
{
    accessibilityLabel: string;
    href: string;
    label: string;
    onClick?: ComponentProps<typeof ButtonLink>["onClick"];
    rel?: ComponentProps<typeof ButtonLink>["rel"];
    role: "link";
    size?: ComponentProps<typeof ButtonLink>["size"];
    target?: ComponentProps<typeof ButtonLink>["target"];
  }
| {
    accessibilityLabel: string;
    label: string;
    onClick: ComponentProps<typeof Button>["onClick"];
    role?: "button";
    size?: ComponentProps<typeof Button>["size"];
  }
-

Adds an optional button for user interaction.
In this case, we use our ButtonGroup component.

thumbnail
{ image: ReactElement; avatar?: never; icon?: never }
| { image?: never; avatar: ReactElement; icon?: never }
| { image?: never; avatar?: never; icon: ReactElement }
-

An optional thumbnail to display next to the text.

title
string
-

Heading of BannerOverlay. Content should be localized. See the Text variant to learn more.

zIndex
Indexable
-

zIndex of BannerOverlay. See the zIndex guidelines to learn more.

Usage guidelines

When to use
  • To provide short educational messages allowing content to scroll underneath
  • To help users learn more about a specific idea or interest
  • To support users when they have performed actions that indicate medium or high intent (related pin tap, idea pin swipe)
When not to use
  • If there is a need to block the content underneath use Modal instead
  • To replace Toast
  • For lengthy messages, forms, or blocks of information. Consider OverlayPanel or new page instead

Best Practices

Do

Use BannerOverlay to educate and provide additional information to users when they have performed actions that indicate some intent, such as a related pin tap or idea pin swipe.

Don't

Use BannerOverlay for critical information, such as errors or warnings. Use BannerCallout instead.

Do

Be concise when writing the content. The BannerOverlay is intended to display short messages. Ideally max of 3 lines.
Please consider localization.

Don't

Display long messages inside the BannerOverlay as it isn't the intent of this component, and it could lead to readability issues considering the component size and space.

Do

Place BannerOverlay out of the way so a user can still navigate and complete tasks.

Please note: On desktop devices, the BannerOverlay should appear at the top of the screen. The BannerOverlay shouldn't block navigation; therefore, it shuld be positioned below the navigation bar.

On mobile devices, the BannerOverlay should appear at the bottom of the screen. The 'offset' prop can be used to adjust the position of the BannerOverlay.

If both top an bottom offset are set, only the bottom offset will be used when mobile device is detected and the only top offset will be used on desktop devices.

In case we need to break this design positioning rule, and place BannerOverlay at the top in mobile devices and at the bottom in desktop devices, you can set the prop 'reverseOffset' to true and invert the logic. If you want to only apply the revert on mobile, you can only prop 'reverseOffset' to true when mobile devices are detected. With this, BannerOverlay will always be positioned at the top.

Don't

Stack multiple BannerOverlays; only one BannerOverlay should appear on the screen per time.

Accessibility

Labels

dismissButton and primaryAction, require a short, descriptive label for screen readers, which should also be localized.

Icons and thumbnails on BannerOverlay are purely decorative, and can therefore have an empty string as the accessibilityLabel. The thumbnail (Image) or Icon should supply an alt or accessibilityLabel, respectively, if the Image or Icon supplies extra context or information.

Variants

Thumbnail

BannerOverlay supports images, icons and avatars as thumbnails.

  • Image: With an image for Pin or Board actions, or the Pinterest logo.
  • Avatar: With an Avatar for Profile or Pinner-related messaging.
  • Icon: For when an icon is needed to represent content that isn’t a pin or a profile.
Image
import { useState } from 'react';
import { BannerOverlay, Button, FixedZIndex, Image, Link, Text } from 'gestalt';

export default function Example() {
  const [showComponent, setShowComponent] = useState(true);

  return !showComponent ? (
    <Button
      onClick={() => {
        setShowComponent(true);
      }}
      text="Show BannerOverlay"
    />
  ) : (
    <BannerOverlay
      message={
        <Text inline>
          Discover trending{' '}
          <Link display="inlineBlock" href="#" target="self">
            fashion
          </Link>{' '}
          ideas in the app!
        </Text>
      }
      offset={{ top: 130, bottom: 24 }}
      onDismiss={() => {
        setShowComponent(false);
      }}
      primaryAction={{
        role: 'button',
        onClick: () => {
          setShowComponent(false);
        },
        label: 'Get the app',
        accessibilityLabel: 'Get the app',
      }}
      thumbnail={{
        image: (
          <Image
            alt="Pinterest Logo"
            naturalHeight={1}
            naturalWidth={1}
            src="https://i.ibb.co/LQc8ynn/image.png"
          />
        ),
      }}
      title="More to Explore"
      zIndex={new FixedZIndex(100)}
    />
  );
}

Avatar
import { useState } from 'react';
import {
  Avatar,
  BannerOverlay,
  Button,
  FixedZIndex,
  Link,
  Text,
} from 'gestalt';

export default function Example() {
  const [showComponent, setShowComponent] = useState(true);

  return !showComponent ? (
    <Button
      onClick={() => {
        setShowComponent(true);
      }}
      text="Show BannerOverlay"
    />
  ) : (
    <BannerOverlay
      message={
        <Text inline>
          Discover trending{' '}
          <Link display="inlineBlock" href="#" target="self">
            fashion
          </Link>{' '}
          ideas in the app!
        </Text>
      }
      offset={{ top: 130, bottom: 24 }}
      onDismiss={() => {
        setShowComponent(false);
      }}
      primaryAction={{
        role: 'button',
        onClick: () => {
          setShowComponent(false);
        },
        label: 'Get the app',
        accessibilityLabel: 'Get the app',
      }}
      thumbnail={{
        avatar: (
          <Avatar name="Keerthi" src="https://i.ibb.co/ZfCZrY8/keerthi.jpg" />
        ),
      }}
      title="More to Explore"
      zIndex={new FixedZIndex(100)}
    />
  );
}

Icon
import { useState } from 'react';
import { BannerOverlay, Button, FixedZIndex, Icon, Link, Text } from 'gestalt';

export default function Example() {
  const [showComponent, setShowComponent] = useState(true);

  return !showComponent ? (
    <Button
      onClick={() => {
        setShowComponent(true);
      }}
      text="Show BannerOverlay"
    />
  ) : (
    <BannerOverlay
      message={
        <Text inline>
          Discover trending{' '}
          <Link display="inlineBlock" href="#" target="self">
            fashion
          </Link>{' '}
          ideas in the app!
        </Text>
      }
      offset={{ top: 130, bottom: 24 }}
      onDismiss={() => {
        setShowComponent(false);
      }}
      primaryAction={{
        role: 'button',
        onClick: () => {
          setShowComponent(false);
        },
        label: 'Get the app',
        accessibilityLabel: 'Get the app',
      }}
      thumbnail={{
        icon: (
          <Icon
            accessibilityLabel="Sparkle"
            color="recommendation"
            icon="sparkle"
          />
        ),
      }}
      title="More to Explore"
      zIndex={new FixedZIndex(100)}
    />
  );
}

Actions

You can have zero, one or two actions using the props primaryAction and `secondaryAction'.

Remember to localize text and any string within primaryAction or dismissButton, as well as title and message.

Please note: Start aligned text is the primary alignment for our Business products. It will be left-aligned in left-to-right languages and right-aligned in right-to-left languages

import { useState } from 'react';
import { BannerOverlay, Button, FixedZIndex, Icon } from 'gestalt';

export default function Example() {
  const [showComponent, setShowComponent] = useState(true);

  return !showComponent ? (
    <Button
      onClick={() => {
        setShowComponent(true);
      }}
      text="Show BannerOverlay"
    />
  ) : (
    <BannerOverlay
      message="You can have up to two buttons in the BannerOverlay!"
      offset={{ top: 130, bottom: 24 }}
      onDismiss={() => {
        setShowComponent(false);
      }}
      primaryAction={{
        role: 'button',
        onClick: () => {
          setShowComponent(false);
        },
        label: 'Primary action',
        accessibilityLabel: 'Primary action',
      }}
      secondaryAction={{
        role: 'button',
        onClick: () => {},
        label: 'Secondary Action',
        accessibilityLabel: 'Secondary Action',
      }}
      thumbnail={{
        icon: (
          <Icon accessibilityLabel="Sparkle" color="info" icon="info-circle" />
        ),
      }}
      title="Call to Action"
      zIndex={new FixedZIndex(100)}
    />
  );
}

Dismissable

BannerOverlay provides a dismiss button affordance. You can optionally have the Call to Action dismiss the BannerOverlay by not setting the dismissButton prop.

Dismiss button
import { useState } from 'react';
import { BannerOverlay, Button, FixedZIndex, Icon } from 'gestalt';

export default function Example() {
  const [showComponent, setShowComponent] = useState(true);

  return !showComponent ? (
    <Button
      onClick={() => {
        setShowComponent(true);
      }}
      text="Show BannerOverlay"
    />
  ) : (
    <BannerOverlay
      message="You can dismiss this banner with the dismiss button!"
      offset={{ top: 130, bottom: 24 }}
      onDismiss={() => {
        setShowComponent(false);
      }}
      thumbnail={{
        icon: (
          <Icon accessibilityLabel="Sparkle" color="info" icon="info-circle" />
        ),
      }}
      title="Dismissable Banner"
      zIndex={new FixedZIndex(100)}
    />
  );
}

Call to Action dismiss
import { useState } from 'react';
import { BannerOverlay, Button, FixedZIndex, Icon } from 'gestalt';

export default function Example() {
  const [showComponent, setShowComponent] = useState(true);

  return !showComponent ? (
    <Button
      onClick={() => {
        setShowComponent(true);
      }}
      text="Show BannerOverlay"
    />
  ) : (
    <BannerOverlay
      message="You can dismiss this banner with the primary action!"
      offset={{ top: 130, bottom: 24 }}
      primaryAction={{
        role: 'button',
        onClick: () => {
          setShowComponent(false);
        },
        label: 'Got it!',
        accessibilityLabel: 'Got it!',
      }}
      thumbnail={{
        icon: (
          <Icon accessibilityLabel="Sparkle" color="info" icon="info-circle" />
        ),
      }}
      title="Dismissable Banner"
      zIndex={new FixedZIndex(100)}
    />
  );
}

Message

The message prop accepts either a string or Text. Use a string for simple messages without any visual style. BannerOverlay will handle the message style and adherence to design guidelines. If a message with more complex style is required, such as bold text or inline links, use Text to wrap your message with any additional Text or Link usages contained within.

import { useState } from 'react';
import { BannerOverlay, Button, FixedZIndex, Image, Link, Text } from 'gestalt';

export default function Example() {
  const [showComponent, setShowComponent] = useState(true);

  return !showComponent ? (
    <Button
      onClick={() => {
        setShowComponent(true);
      }}
      text="Show BannerOverlay"
    />
  ) : (
    <BannerOverlay
      message={
        <Text inline>
          Discover{' '}
          <Link display="inlineBlock" href="#" target="self">
            trending fashion ideas
          </Link>{' '}
          in the app!
        </Text>
      }
      offset={{ top: 130, bottom: 24 }}
      onDismiss={() => {
        setShowComponent(false);
      }}
      primaryAction={{
        role: 'button',
        onClick: () => {
          setShowComponent(false);
        },
        label: 'Get the app',
        accessibilityLabel: 'Get the app',
      }}
      secondaryAction={{
        role: 'button',
        onClick: () => {},
        label: 'Not now',
        accessibilityLabel: 'Not now',
      }}
      thumbnail={{
        image: (
          <Image
            alt="Pinterest Logo"
            naturalHeight={1}
            naturalWidth={1}
            src="https://i.ibb.co/LQc8ynn/image.png"
          />
        ),
      }}
      title="More to Explore"
      zIndex={new FixedZIndex(100)}
    />
  );
}

Responsive

BannerOverlay is responsive to different devices. Therefore, BannerOverlay dweb is set to a max width of 900 px to preserve a great usability experience and consistency with other components.

On desktop devices, the BannerOverlay should appear at the top of the screen (below navigation). The BannerOverlay shouldn't block navigation.
On mobile devices, the BannerOverlay should appear at the bottom of the screen. The 'offset' prop can be used to adjust the position of the BannerOverlay.

Writing

Do
  • Use succinct and scannable language that clearly conveys support to the user
  • Consider internationalization and how other languages may be constrained
  • Write up to 2 lines of text.
Don't
  • Write messages that are wordy and take up a lot of space, as the BannerOverlay is intended to short messages
  • Write content that takes more than 2 lines of text
  • Truncate content. If the message needs more words, consider a different component

BannerUpsell
BannerUpsell banners are used for paid upgrades, free trials, or marketing promotions.

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

Toast
Toasts educate users on the content of the screen, provide confirmation when people complete an action, or simply communicate a short message.