Skip to content

Growth Box [WIP]

beta

The Growth Box is a composition pattern built on the Card component. Use it for contextual upgrade prompts, plan-limit notices, and other lightweight growth messages.

This pattern is only used in the bottom left of the navigation — at the top of the sidebar footer list, above alerts, support links, and the user profile.

The card pairs a short headline with supporting copy and a right-aligned action row.

Default

Usage

Default

.cn-growth-card {
width: 100%;
}
.cn-growth-card-actions {
margin-top: var(--cn-spacing-3);
}
.cn-growth-card .cn-card-content {
font-size: var(--cn-font-size-3);
line-height: 1.428;
letter-spacing: var(--cn-tracking-tight);
}
/*
* Primary CTA border — Figma: border/brand @ 16% → set/purple/primary @ 87%, 90deg.
* Do not use Button variant="ai"; its multi-stop border fights this override.
*/
.cn-button.cn-growth-card-cta {
color: var(--cn-set-ai-outline-text) !important;
background-color: transparent !important;
background-image:
linear-gradient(var(--cn-bg-1), var(--cn-bg-1)),
linear-gradient(
90deg,
var(--cn-border-brand) 16%,
var(--cn-set-purple-primary-bg) 87%
) !important;
background-origin: border-box !important;
background-clip: padding-box, border-box !important;
background-size:
100% 100%,
100% 100% !important;
border: var(--cn-btn-border) solid transparent !important;
box-shadow: none !important;
}
import { Button, Card, IconV2, Text } from "@harnessio/ui";
const [visible, setVisible] = React.useState(true);
if (!visible) {
return (
<div className="flex items-center gap-cn-xs">
<Text color="foreground-3">Growth box dismissed — don't show the same message after dismissal</Text>
<Button variant="link" size="xs" onClick={() => setVisible(true)}>
<IconV2 name="refresh" size="xs" />
Refresh
</Button>
</div>
);
}
{/* Parent sets width (e.g. sidebar column); card fills it via width: 100% */}
<div style={{ width: 220 }}>
<Card.Root size="sm" interactive={false} className="cn-growth-card">
<Card.Title>Setup is almost finished</Card.Title>
<Card.Content>Only a few minutes left to complete your pipeline.</Card.Content>
<div className="flex justify-end gap-cn-xs cn-growth-card-actions">
<Button variant="ghost" size="xs" onClick={onDismiss}>
Dismiss
</Button>
<Button variant="secondary" size="xs" className="cn-growth-card-cta" onClick={onPrimary}>
Finish setup
</Button>
</div>
</Card.Root>
</div>

Anatomy

ElementComponentGuidance
PlacementSidebar footerBottom left of the navigation only — first item above alerts, support, and profile
ContainerCard.RootUse size="sm", interactive={false}, and className="cn-growth-card" for body small typography
HeadlineCard.TitleOne short sentence stating the value or constraint
BodyCard.ContentBody small (text-cn-size-3 / 12px). Apply via cn-growth-card on the card root
Action rowcn-growth-card-actionsAdds spacing above the action buttons. Use size="xs" on all buttons
DismissButton (variant="ghost", size="xs")Removes the card from view
Primary actionButton (variant="secondary", className="cn-growth-card-cta", size="xs")Main CTA. Gradient border only: border/brand @ 16% → set/purple/primary @ 87% (90deg). Not variant="ai".

Guidelines

  • Bottom-left navigation only. Place the box at the top of the sidebar footer list — above alerts, support links, and the user profile.
  • Keep copy brief. The box should scan in one glance: headline, one supporting line, then actions.
  • Right-align actions. Place dismiss and primary CTA in a horizontal row at the bottom-right of the card.
  • Respect dismissal. Persist dismiss state per message — don’t show the same message after dismissal.
  • Constrain width via the parent. Growth boxes fill their container (width: 100% on cn-growth-card). Place them in a ~220px parent (e.g. the sidebar column); do not hard-code max-width on the card.