UI Library

Single pricing card

One plan, one price, a checklist of what it includes, and a single call to action. The honest shape for a product that has not split into tiers yet.

Pricingsingle-tierchecklistcard
Preview
Current plan
Free
— for every user, every workspace.
  • Unlimited projects, tasks and notes.
  • Unlimited workspaces and members.
  • Two-way sync with the editor extensions.
  • Optional repository sync.
  • EU hosting, opt-out analytics, no cross-site tracking.
apps/site/blocks/components/pricing-single-card.tsx
import { Check } from 'lucide-react';

const DEFAULT_FEATURES = [
  'Unlimited projects, tasks and notes.',
  'Unlimited workspaces and members.',
  'Two-way sync with the editor extensions.',
  'Optional repository sync.',
  'EU hosting, opt-out analytics, no cross-site tracking.',
];

export function PricingSingleCard({
  eyebrow = 'Current plan',
  price = 'Free',
  note = '— for every user, every workspace.',
  features = DEFAULT_FEATURES,
  cta = { label: 'Sign in', href: '#' },
}: {
  eyebrow?: string;
  price?: string;
  note?: string;
  features?: string[];
  cta?: { label: string; href: string };
}) {
  return (
    <div className="mx-auto max-w-2xl px-4 py-16 sm:px-6">
      <div className="rounded-xl border border-border bg-card p-8">
        <div className="text-xs font-medium uppercase tracking-widest text-primary">{eyebrow}</div>

        {/* items-baseline so the note sits on the price's baseline rather than
            centring against a 4xl line box. */}
        <div className="mt-2 flex items-baseline gap-2">
          <div className="text-4xl font-semibold tracking-tight">{price}</div>
          <div className="text-sm text-muted-foreground">{note}</div>
        </div>

        <ul className="mt-6 space-y-2 text-sm">
          {features.map((line) => (
            <li key={line} className="flex items-start gap-2">
              <Check className="mt-0.5 h-4 w-4 shrink-0 text-primary" />
              <span>{line}</span>
            </li>
          ))}
        </ul>

        <div className="mt-8">
          <a
            href={cta.href}
            className="inline-flex h-10 items-center rounded-md bg-primary px-5 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90"
          >
            {cta.label}
          </a>
        </div>
      </div>
    </div>
  );
}

Dependencies

  • lucide-react — npm package

Colours come from CSS variables (--background, --primary, --border) using the shadcn/ui token names, so the block adopts your palette rather than importing ours.