Skip to content

Pricing card

Compose three of these in a row for a SaaS pricing page.

'use client';
import type { ReactNode } from 'react';
import { Badge, Button, Card, Stack, Text } from '@helixui/core';
import { Check } from '@helixui/icons';
export interface PricingCardProps {
tier: string;
price: ReactNode;
per?: ReactNode;
description?: ReactNode;
features: string[];
ctaLabel: string;
onCta?: () => void;
/** Highlight this tier as recommended. Adds a badge + brand tone. */
highlight?: boolean;
}
export function PricingCard({
tier,
price,
per = '/ month',
description,
features,
ctaLabel,
onCta,
highlight = false,
}: PricingCardProps) {
return (
<Card
variant={highlight ? 'elevated' : 'outlined'}
style={{
padding: 'var(--helixui-space-6)',
position: 'relative',
borderColor: highlight ? 'var(--helixui-color-border-action-brand)' : undefined,
}}
>
<Stack gap={4}>
<Stack gap={1} direction="row" align="center" justify="between">
<Text weight="semibold" size="lg">{tier}</Text>
{highlight ? <Badge tone="brand">Recommended</Badge> : null}
</Stack>
<Stack gap={0} direction="row" align="baseline" wrap>
<Text size="4xl" weight="bold">{price}</Text>
{per ? <Text size="sm" tone="muted">&nbsp;{per}</Text> : null}
</Stack>
{description ? <Text size="sm" tone="muted">{description}</Text> : null}
<Stack gap={2}>
{features.map((f) => (
<Stack key={f} direction="row" gap={2} align="center">
<span style={{ color: 'var(--helixui-color-text-action-brand)' }} aria-hidden><Check /></span>
<Text size="sm">{f}</Text>
</Stack>
))}
</Stack>
<Button
tone={highlight ? 'brand' : 'neutral'}
variant={highlight ? 'solid' : 'outline'}
onClick={onCta}
>
{ctaLabel}
</Button>
</Stack>
</Card>
);
}

Usage

<Stack direction="row" gap={4} wrap>
<PricingCard
tier="Hobby"
price="$0"
description="Everything you need to ship a side project."
features={['All core components', '265 icons', 'Single seat']}
ctaLabel="Start free"
/>
<PricingCard
tier="Pro"
price="$29"
description="For small teams that ship more."
features={['All Hobby', 'Up to 10 seats', 'Priority support']}
ctaLabel="Start Pro"
highlight
/>
<PricingCard
tier="Team"
price="$99"
description="For organizations that need controls."
features={['All Pro', 'Unlimited seats', 'SSO + audit log']}
ctaLabel="Talk to sales"
/>
</Stack>

Design notes

  • Only one tier gets highlight. If two are “recommended,” neither is.
  • The price + per render as one row at the baseline — text alignment matters here; the cents/units shouldn’t visually outweigh the number.
  • The check column uses a brand-colored glyph regardless of tier; the tier itself doesn’t need to change brand color for variety.