Highlight dialog
The dialog that announces one new thing: a feature, a section, a new layout. A square media slot, a short eyebrow, a title, one or two sentences, and two actions: one dismisses it, the other takes the person to what is new.
Anatomy
A Dialog with its own layout, built on the Dialog, AspectRatio and Button atoms from the design system's Figma (Highlight / Dialog). Open it to see the parts.
- 1Media
A square slot (1:1). Whatever you pass is stretched to cover it: an image, a video, an animation. From lg it fills the left half edge to edge; below lg it sits inside the padding with a 10px radius. Ships as a dashed placeholder.
- 2Close
The Dialog's own X, top right. Below lg it sits in a 64px header bar; from lg it sits over the text column.
- 3Eyebrow
text-xs, bold, in the primary text colour, drawn in capitals. Says what kind of news this is: New feature. Write it in sentence case, the component capitalises it. Optional.
- 4Title
text-lg, semibold. The name of the thing, or what changed.
- 5Description
text-sm, muted. One or two sentences on what it is for. Optional.
- 6Actions
A bordered footer with two buttons: outline to dismiss (Got it!) and Primary to go to the feature (Check it out). Side by side on the right from sm; stacked and full width under sm, Primary first.
Responsive
One component, three layouts, chosen by the viewport. From lg (1024px): 800px wide, media on the left half and text on the right. From sm (640px): 552px wide, a header bar, then media over text. Under sm: the whole screen, same stack, the two buttons full width. The toggle below shows the last two; for the side-by-side one, open the dialog above on a window at least 1024px wide.
Recipes
The person asks for it: a button or a menu item opens the dialog. Pass that element as trigger and the component handles open and close.
<HighlightDialog
trigger={<Button>What's new</Button>}
eyebrow="New feature"
title="Custom checkouts"
description="Build a separate checkout for each market or campaign, each with its own payment methods."
media={<img src="/whats-new/custom-checkouts.png" alt="" />}
primaryLabel="Check it out"
onPrimary={() => router.push("/checkout/custom")}
/>The dialog opens by itself the first time someone reaches the section and never again. Drive open yourself, and treat every way out (the X, Got it!, Esc, the primary action) as seen. Press the button to simulate a first visit.
// `seen` comes from wherever the product remembers it (the user's settings).
const [seen, setSeen] = React.useState(false);
<HighlightDialog
open={!seen}
onOpenChange={(open) => { if (!open) setSeen(true); }}
eyebrow="New feature"
title="Custom checkouts"
description="Build a separate checkout for each market or campaign, each with its own payment methods."
primaryLabel="Check it out"
onPrimary={() => { setSeen(true); router.push("/checkout/custom"); }}
/>Import
Copy this import line at the top of the file where you compose this molecule.
import { HighlightDialog } from "@/components/patterns/highlight-dialog";Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string (required) | — | The dialog title, and its accessible name. |
| primaryLabel | string (required) | — | Label of the Primary button, the one that takes the person to the feature. |
| onPrimary | () => void | — | Called when the Primary button is pressed. Closing the dialog here is up to you. |
| secondaryLabel | string | "Got it!" | Label of the outline button. It always closes the dialog. |
| onSecondary | () => void | — | Called when the outline button is pressed, before the dialog closes. |
| eyebrow | string | — | Short label over the title, drawn in capitals. Leave it out to hide it. |
| description | React.ReactNode | — | One or two sentences under the title. |
| media | React.ReactNode | dashed placeholder | What fills the square slot. It is stretched to cover it (object-cover). |
| trigger | React.ReactNode | — | The element that opens the dialog. Leave it out when you drive open yourself. |
| open / defaultOpen | boolean | — | Controlled or uncontrolled open state. |
| onOpenChange | (open: boolean) => void | — | Fires on every open and close, whatever caused it. |
| className | string | — | Extra classes on the dialog surface. |
When to use
- To announce one new feature, section or layout, with something to look at.
- As the door to a guided tour: the Primary button starts it.
- From a What's new entry the person opens on their own.
When not to use
- To ask for a confirmation: use Alert dialog.
- For a form or a decision with fields: use Dialog.
- For a small tip on one control: use Popover.
- For an error or a warning: use Alert.
Usage
- One announcement per dialog.
- Keep the description to one or two sentences.
- Make the Primary button lead somewhere: the feature itself, or its tour.
- When it opens by itself, show it once.
- Don't chain several highlights one after another.
- Don't add a third action.
- Don't put text inside the media; it will not be translated or read aloud.
- Don't open it by itself over a task the person is in the middle of.
Related
Cross-links to the atoms this molecule composes and sibling patterns.
- DialogThe atom this molecule is built on.
- Aspect ratioKeeps the media slot square.
- PopoverFeature tutorials and tips anchored to one element.
- Guide cardThe other piece with a media slot, for a grid on a page rather than an announcement.