BannerUpsell
Props
Usage guidelines
- Displaying promotional information to a user that is not tied to a task or state on the surface.
- Sharing updates or changes to the features and offerings of the product.
- Anything related to state or status within the surface. Consider a BannerCallout instead.
- Promoting or highlighting specific elements / areas within a surface. Let the team know if this is needed.
Best practices
Use BannerUpsells for marketing new products or encouraging upgrades.
Place BannerUpsell at the top of the page under the primary navigation when possible.
Plan for the timing of your BannerUpsells with new product launches. Try to create different messages for each time an BannerUpsell appears to the user.
Use BannerUpsells for critical information, such as errors or warnings. Use BannerCallout instead. BannerUpsells should not be used for general information either.
Stack BannerUpsells on a page. In the case that they must be stacked, BannerCallouts will appear above BannerUpsells.
Keep showing the same BannerUpsell once it has been dismissed. BannerUpsells should only appear a maximum of 2 times to the same user, as they have diminishing returns.
Accessibility
Labels
dismissButton
, primaryAction
, secondaryAction
, and submitButtonAccessibilityLabel
each require a short, descriptive label for screen readers, which should also be localized.
In the case of action
Buttons or
Links, alternative text should be provided through the accessibilityLabel
prop to replace vague text like "Visit" or "Learn more" with more descriptive information, like "Learn more about work from home resources". Avoid using the words "button" or "link" in the label, as this becomes repetitive. If the action text is already descriptive, an empty string can be passed.
For the dismissButton
IconButton, the label provided should indicate the intent, like “Dismiss this banner”.
The
Image or
Icon supplied to imageData
should only supply an alt
or accessibilityLabel
, respectively, if the Image or Icon supplies extra context or information. Icons in BannerUpsells are often purely decorative, and can therefore have an empty string as the accessibilityLabel
.
import { BannerUpsell, Box, Icon } from 'gestalt'; export default function Example() { return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <BannerUpsell dismissButton={{ accessibilityLabel: 'Dismiss banner', onDismiss: () => {}, }} imageData={{ component: ( <Icon accessibilityLabel="" color="default" icon="pinterest" size={32} /> ), }} message="Earn $60 of ads credit, and give $30 of ads credit to a friend" primaryAction={{ href: 'https://pinterest.com', label: 'Send invite', accessibilityLabel: 'Invite friend to use ads', target: 'blank', role: 'link', }} secondaryAction={{ accessibilityLabel: 'Learn more: Verified Merchant Program', href: 'https://help.pinterest.com/en/business/article/verified-merchant-program', label: 'Learn more', target: 'blank', role: 'link', }} title="Give $30, get $60 in ads credit" /> </Box> ); }
Localization
Be sure to localize all text strings. Note that localization can lengthen text by 20 to 30 percent.
Note that dismissButton.accessibilityLabel
is optional as DefaultLabelProvider provides default strings. Use custom labels if they need to be more specific.
import { BannerUpsell, Box, DefaultLabelProvider, Icon } from 'gestalt'; export default function Example() { return ( <DefaultLabelProvider labels={{ BannerUpsell: { accessibilityDismissButtonLabel: 'Dismiss banner', }, }} > <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <BannerUpsell dismissButton={{ onDismiss: () => {} }} imageData={{ component: ( <Icon accessibilityLabel="" color="default" icon="send" size={32} /> ), }} message="Verfolgen Sie die Anzeigenkonvertierung - Umsatz, Traffic und mehr - mit dem Pinterest Tag" primaryAction={{ label: 'Beanspruche jetzt', accessibilityLabel: 'Beanspruche Guthaben jetzt', role: 'button', onClick: () => {}, }} title="Fast fertig! Beenden Sie die Installation Ihres Pinterest-Tags und erhalten Sie ein Guthaben von 10 Euro" /> </Box> </DefaultLabelProvider> ); }
Subcomponents
BannerUpsell.Form
BannerUpsell.Form can be used to add a short form to BannerUpsell for collecting data from the user.
BannerUpsell.Form Props
Variants
Text-only
Used to convey a short message that requires no action, except dismiss.
import { BannerUpsell, Box } from 'gestalt'; export default function Example() { return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <BannerUpsell dismissButton={{ accessibilityLabel: 'Dismiss this banner', onDismiss: () => {}, }} message="Single line BannerUpsell with no title or call to action." /> </Box> ); }
Icon
The Icon is used to add additional meaning to the BannerUpsell. The icon can reference a Pinterest product, feature or an action from our Icon library.
import { BannerUpsell, Box, Icon } from 'gestalt'; export default function Example() { return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <BannerUpsell dismissButton={{ accessibilityLabel: 'Dismiss banner', onDismiss: () => {}, }} imageData={{ component: ( <Icon accessibilityLabel="" color="default" icon="pinterest" size={32} /> ), }} message="Earn $60 of ads credit, and give $30 of ads credit to a friend" primaryAction={{ href: 'https://pinterest.com', label: 'Send invite', accessibilityLabel: 'Invite friend to use ads', target: 'blank', role: 'link', }} title="Give $30, get $60 in ads credit" /> </Box> ); }
Image
The Image in BannerUpsell is used to add visual interest and draw the user’s attention. Images should relate to the message of the BannerUpsell. BannerUpsell images should use approved photography or be illustrations using our brand colors. Images will always be 128px wide.
import { BannerUpsell, Box, Image } from 'gestalt'; export default function Example() { return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <BannerUpsell dismissButton={{ accessibilityLabel: 'Dismiss banner', onDismiss: () => {}, }} imageData={{ component: ( <Image alt="" color="rgb(231, 186, 176)" naturalHeight={751} naturalWidth={564} src="https://i.ibb.co/7bQQYkX/stock2.jpg" /> ), mask: { rounding: 4 }, width: 128, }} message="Check out our resources for adapting to these times." primaryAction={{ href: 'https://pinterest.com', label: 'Visit', accessibilityLabel: 'Visit our Stay Safe resources', target: 'blank', role: 'link', }} title="Stay healthy and safe" /> </Box> ); }
Actions
BannerUpsells can have either one primary action, or a primary action and a secondary action. These actions can be buttons, when no `href` is supplied, or links, by specifying the `href` property.
BannerUpsell actions with link interaction can be paired with GlobalEventsHandlerProvider. See GlobalEventsHandlerProvider to learn more about link navigation.
For example, “Learn more” may link to a separate documentation site, while “Send invite” could be a button that opens a Modal with an invite flow. Be sure to localize the labels of the actions.
If needed, actions can become disabled after clicking by setting disabled: true
in the action data.
import { useState } from 'react'; import { BannerUpsell, Box, Button, ButtonGroup, Column, Flex, Label, Layer, Modal, Text, TextArea, TextField, } from 'gestalt'; export default function Example() { const [showModal, setShowModal] = useState(false); return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <Box marginEnd={-1} marginStart={-1}> <BannerUpsell dismissButton={{ accessibilityLabel: 'Dismiss banner', onDismiss: () => {}, }} message="Earn $60 of ads credit, and give $30 of ads credit to a friend" primaryAction={{ accessibilityLabel: 'Send ads invite', label: 'Send invite', onClick: () => { setShowModal(!showModal); }, role: 'button', }} secondaryAction={{ accessibilityLabel: 'Learn more: Verified Merchant Program', href: 'https://help.pinterest.com/en/business/article/verified-merchant-program', label: 'Learn more', target: 'blank', role: 'link', }} title="Give $30, get $60 in ads credit" /> {showModal && ( <Layer> <Modal accessibilityModalLabel="Invite a friend to the Verified Merchant Program" footer={ <Flex flex="grow" justifyContent="end"> <ButtonGroup> <Button onClick={() => { setShowModal(!showModal); }} size="lg" text="Cancel" /> <Button color="red" size="lg" text="Send invite" /> </ButtonGroup> </Flex> } heading="Verified Merchant Program Invitation" onDismiss={() => { setShowModal(!showModal); }} size="md" subHeading="When your friend spends their first $30 on ads, you’ll earn $60 of ads credit, and they’ll get $30 of ads credit, too." > <Flex direction="row"> <Column span={12}> <Box display="flex" paddingX={8} paddingY={2}> <Column span={4}> <Label htmlFor="name"> <Text align="forceLeft" weight="bold"> Friend's Name </Text> </Label> </Column> <Column span={8}> <TextField id="name" onChange={() => undefined} /> </Column> </Box> <Box display="flex" paddingX={8} paddingY={2}> <Column span={4}> <Label htmlFor="email"> <Text align="forceLeft" weight="bold"> Friend's E-mail </Text> </Label> </Column> <Column span={8}> <TextField id="email" onChange={() => undefined} /> </Column> </Box> <Box display="flex" paddingX={8} paddingY={2}> <Column span={4}> <Label htmlFor="desc"> <Text align="forceLeft" weight="bold"> Personal Message </Text> </Label> </Column> <Column span={8}> <TextArea id="desc" onChange={() => undefined} /> </Column> </Box> </Column> </Flex> </Modal> </Layer> )} </Box> </Box> ); }
Forms
Inputs can be added to BannerUpsells to collect information from users (ex: name or email) through the use of BannerUpsell.Form
. Most BannerUpsells should have no more than 2 inputs. If more inputs are needed, direct users to a full page using the primaryAction
.
import { useState } from 'react'; import { BannerUpsell, Box, Icon, TextField } from 'gestalt'; export default function FormExample() { const [value, setValue] = useState(''); const handleSubmit = ({ event }) => { event.preventDefault(); // your submit logic using state values }; return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <BannerUpsell dismissButton={{ accessibilityLabel: 'Dismiss banner', onDismiss: () => {}, }} imageData={{ component: ( <Icon accessibilityLabel="Pin" color="default" icon="pinterest" size={32} /> ), }} message="Earn $60 of ads credit, and give $30 of ads credit to a friend" title="Give $30, get $60 in ads credit" > <BannerUpsell.Form onSubmit={handleSubmit} submitButtonAccessibilityLabel="Submit name for ads credit" submitButtonText="Submit" > <TextField id="nameField" label="Full name" labelDisplay="hidden" onChange={(e) => setValue(e.value)} placeholder="Name" value={value} /> </BannerUpsell.Form> </BannerUpsell> </Box> ); }
import { useState } from 'react'; import { BannerUpsell, Box, Image, TextField } from 'gestalt'; export default function Example() { const [nameValue, setNameValue] = useState(''); const [emailValue, setEmailValue] = useState(''); const handleSubmit = ({ event }) => { event.preventDefault(); // your submit logic using state values }; return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <BannerUpsell dismissButton={{ accessibilityLabel: 'Dismiss banner', onDismiss: () => {}, }} imageData={{ component: ( <Image alt="Succulent plant against pink background" color="rgb(231, 186, 176)" naturalHeight={751} naturalWidth={564} src="https://i.ibb.co/7bQQYkX/stock2.jpg" /> ), mask: { rounding: 4 }, width: 128, }} message="Learn how to grow your business with a Pinterest ads expert today!" title="Interested in a free ads consultation?" > <BannerUpsell.Form onSubmit={handleSubmit} submitButtonAccessibilityLabel="Submit info for contact" submitButtonText="Contact me" > <Box display="block" smDisplay="flex"> <Box flex="grow" marginBottom={2} marginEnd={0} smMarginBottom={0} smMarginEnd={1} > <TextField id="name" label="Full name" labelDisplay="hidden" onChange={({ value }) => setNameValue(value)} placeholder="Name" value={nameValue} /> </Box> <Box flex="grow" marginStart={0} smMarginStart={1}> <TextField id="email" label="Email address" labelDisplay="hidden" onChange={({ value }) => setEmailValue(value)} placeholder="Email" type="email" value={emailValue} /> </Box> </Box> </BannerUpsell.Form> </BannerUpsell> </Box> ); }
Message
The message
prop accepts either a string or
Text. Use a string for simple messages without any visual style. BannerUpsell will handle the text style and adherence to design guidelines.
If the message
text requires more complex style, such as bold text or inline links, use Text to wrap your message with any additional Text or Link usages contained within. When passing in your own Text component for text
, do not specify color
or align
Text.
import { BannerUpsell, Box, Flex, Link, Text } from 'gestalt'; export default function Example() { return ( <Box alignItems="center" display="flex" height="100%" justifyContent="center" padding={8} > <Flex direction="column" gap={6}> <Text weight="bold">Simple message string</Text> <BannerUpsell message="Earn $60 of ads credit, and give $30 of ads credit to a friend" title="Give $30, get $60 in ads credit" /> <Text weight="bold">Rich message with Text component</Text> <BannerUpsell message={ <Text inline> Earn $60 of ads credit, and give $30 of ads credit to a friend.{' '} <Link accessibilityLabel="Learn more about credit" display="inline" href="#Message" > Learn more </Link> </Text> } title="Give $30, get $60 in ads credit" /> </Flex> </Box> ); }
Component quality checklist
Quality item | Status | Status description |
---|---|---|
Figma Library | Ready | Component is available in Figma for web and mobile web. |
Responsive Web | Ready | Component responds to changing viewport sizes in web and mobile web. |
Related
BannerCallout
Use BannerCallout when communicating critical information, such as an error or warning. BannerCallout can also be used to present the user with general information and further actions they can take, like the successful creation of a business account.
Toast
Toast provides feedback on a user interaction, like a confirmation that appears when a Pin has been saved. Unlike BannerUpsell and BannerCallout, Toasts don’t contain actions. They’re also less persistent, and disappear after a certain duration.
ActivationCard
ActivationCards are used in groups to communicate a user’s stage in a series of steps toward an overall action.