Promo Card
ProThe in-app feature promotion for dashboards: a product eyebrow, a short pitch and one quiet action, beside a framed peek of the feature that runs off the card's edge and dissolves into it.
Installation#
Usage#
Promo Card is composed from named parts, like Card. The PromoCard root owns the surface, the density and the open state; PromoCardContent is the copy column and PromoCardMedia the peek beside it.
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Anatomy#
import {
PromoCard,
PromoCardClose,
PromoCardContent,
PromoCardEyebrow,
PromoCardIcon,
PromoCardTitle,
PromoCardDescription,
PromoCardActions,
PromoCardMedia,
} from "@/components/ui/promo-card"
<PromoCard>
<PromoCardClose />
<PromoCardContent>
<PromoCardEyebrow>
<PromoCardIcon />
</PromoCardEyebrow>
<PromoCardTitle />
<PromoCardDescription />
<PromoCardActions>…</PromoCardActions>
</PromoCardContent>
<PromoCardMedia>…</PromoCardMedia>
</PromoCard>Variants#
default is a contour with no fill, so it sits on whatever ground the dashboard has. muted and brand are deliberate tints that set a promo apart from the data cards around it, and elevated fills and lifts for a promo that floats over a busy page.
Media#
The peek is a tray with a screen inside it. It starts on the eyebrow’s line, runs off the right and bottom edges, and fades out to the right through a mask, so it dissolves into any theme’s ground. Put live components in it (every example above is built from DS parts) or an <img>, which fills the screen from the top-left. On a phone the peek stacks under the copy and holds its own aspect ratio. It is a picture of the product, so it is aria-hidden and inert by default.
Without media#
Every part can be left out. Without a PromoCardMedia the card collapses to one column and drops its resting height; without an eyebrow the pitch still lands on the same baseline. Two text-only promos fit side by side in a dashboard row.
Dismissible#
Add a PromoCardClose and the card can be dismissed: it fades out with a slight settle, then leaves the tree. The root works uncontrolled out of the box; pass open and onOpenChange to keep the choice, which is where a dashboard stores “don’t show this again”.
Density#
Density is Koala’s cross-cutting spacing axis (see Density). For Promo Card it tunes the padding, the resting height and the type step. compact is the app default; comfortable gives an onboarding or empty dashboard more room. The peek re-aligns to the copy at both.
API reference#
PromoCard
The root: owns the surface, the density and the open state, and is a size container (it stacks the peek below 42rem of its own width). Forwards native <div> props. Every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "muted" | "brand" | "elevated" | "default" | default is an unfilled contour; muted and brand are tints; elevated floats on the card fill. |
| density | "comfortable" | "compact" | - | Padding, resting height and type step. Inherits the nearest DensityProvider (compact with none). |
| open | boolean | - | Visibility, controlled. Omit for the built-in behaviour. |
| defaultOpen | boolean | true | Initial visibility, uncontrolled. |
| onOpenChange | (open: boolean) => void | - | Called when PromoCardClose dismisses the card: persist the choice here. The exit plays before it unmounts. |
| Data attribute | Description |
|---|---|
| data-state | open, or closed while the exit plays. |
PromoCardContent
The copy column. Forwards native <div> props.
PromoCardEyebrow
The product line above the title; lead it with your app's mark (<BrandMark wordmark={false} /> in Koala). Forwards native <div> props.
PromoCardIcon
A tile for another product's logo <img>, sized like the BrandMark tile. aria-hidden. Renders a <span>.
PromoCardTitle
The pitch, in one line or two. Forwards native <div> props.
PromoCardDescription
The supporting sentence. Forwards native <p> props.
PromoCardActions
The action row. Forwards native <div> props.
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "sm" | "md" | "lg" | "sm" | Control size imposed on the buttons inside; a Button's own size wins. |
| Data attribute | Description |
|---|---|
| data-control-size | The imposed size. |
PromoCardMedia
The peek: a framed screen cropped by the card's edges, holding an <img> or live DS parts. aria-hidden and inert by default; pass aria-hidden={false} inert={false} to expose it.
PromoCardClose
The dismiss control, top-right: a ghost icon Button. Forwards Button props.
| Prop | Type | Default | Description |
|---|---|---|---|
| aria-label | string | "Dismiss" | The accessible name and tooltip. |
