Skip to content
Neat LabsJoin the waitlist

Pricing tiers

Plan cards with price, summary, features, and an action. One plan can carry the accent border.

id pricing-tiers · revision 1244e13abde7 · catalogue 0.1.0

Preview

Every token this component reads is set by the style, and every font is loaded or a system font.

Desktop, 1280px, lightOpen alone
Phone, 390px, lightOpen alone
Desktop, 1280px, darkOpen alone
Phone, 390px, darkOpen alone

Hover and keyboard focus

The component's own hover and focus styles, switched on for every link and button at once so you can see them without a mouse. In the previews above they work as usual.

Hover, desktop, lightOpen alone
Keyboard focus, desktop, lightOpen alone

Copy it

These two files are exactly what the previews above render. The MCP tool get_component returns the same files.

  1. Save PricingTiers.tsx with your components and styles/neat-paper.css with your styles.
  2. Import styles/neat-paper.css once, after @import "tailwindcss" in your global stylesheet.
  3. Make sure Tailwind scans the folder that holds the component.
  4. For dark mode, set data-theme="dark" on the <html> element.
  5. Add <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,[email protected],600&display=swap"> to the document head.
components/PricingTiers.tsx
export interface Plan {
  name: string;
  price: string;
  period?: string;
  summary: string;
  features: string[];
  action: { label: string; href: string };
  highlighted?: boolean;
}

export interface PricingTiersProps {
  heading?: string;
  plans?: Plan[];
}

const columns: Record<number, string> = { 2: "md:grid-cols-2", 3: "md:grid-cols-3", 4: "md:grid-cols-4" };

const focusRing =
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--nl-focus)]";

/**
 * Two to four plan cards side by side. One plan can be highlighted with the
 * accent border and a "Most teams pick this" label.
 */
export function PricingTiers({
  heading = "Pricing",
  plans = [
    {
      name: "Solo",
      price: "$0",
      period: "per month",
      summary: "For one person trying it on a side project.",
      features: ["One repository", "Drafts for every merge", "Markdown export"],
      action: { label: "Start free", href: "#solo" },
    },
    {
      name: "Team",
      price: "$24",
      period: "per seat, per month",
      summary: "For teams that publish on a schedule.",
      features: ["Unlimited repositories", "Approval workflow", "Email and in-app notes", "Weekly digest"],
      action: { label: "Start a trial", href: "#team" },
      highlighted: true,
    },
    {
      name: "Company",
      price: "Talk to us",
      summary: "For several products and custom review rules.",
      features: ["Everything in Team", "SSO", "Audit log"],
      action: { label: "Contact sales", href: "#company" },
    },
  ],
}: PricingTiersProps) {
  return (
    <section className="bg-[color:var(--nl-canvas)] px-6 py-[var(--nl-section-y)] font-[family-name:var(--nl-font-sans)] text-[color:var(--nl-ink)]">
      <div className="mx-auto max-w-6xl">
        <h2 className="text-center font-[family-name:var(--nl-font-display)] text-3xl font-semibold sm:text-4xl">{heading}</h2>
        <ul className={`mt-12 grid gap-6 ${columns[plans.length] ?? "md:grid-cols-3"}`}>
          {plans.map((plan) => (
            <li
              key={plan.name}
              className={`flex flex-col rounded-[var(--nl-radius)] border bg-[color:var(--nl-surface)] p-6 ${
                plan.highlighted ? "border-2 border-[color:var(--nl-accent)]" : "border-[color:var(--nl-line)]"
              }`}
            >
              {plan.highlighted ? (
                <p className="mb-3 font-[family-name:var(--nl-font-mono)] text-xs uppercase tracking-wider text-[color:var(--nl-muted)]">
                  Most teams pick this
                </p>
              ) : null}
              <h3 className="text-lg font-semibold">{plan.name}</h3>
              <p className="mt-4">
                <span className="font-[family-name:var(--nl-font-display)] text-4xl font-semibold">{plan.price}</span>
                {plan.period ? <span className="ml-2 text-sm text-[color:var(--nl-muted)]">{plan.period}</span> : null}
              </p>
              <p className="mt-3 text-sm text-[color:var(--nl-muted)]">{plan.summary}</p>
              <ul className="mt-6 flex-1 space-y-2 text-sm">
                {plan.features.map((feature) => (
                  <li key={feature} className="flex gap-2">
                    <span aria-hidden="true" className="text-[color:var(--nl-accent)]">&#10003;</span>
                    {feature}
                  </li>
                ))}
              </ul>
              <a
                href={plan.action.href}
                className={`mt-8 rounded-[var(--nl-radius)] px-4 py-2.5 text-center font-medium ${
                  plan.highlighted
                    ? "bg-[color:var(--nl-accent)] text-[color:var(--nl-accent-ink)] hover:opacity-90"
                    : "border border-[color:var(--nl-line)] hover:bg-[color:var(--nl-canvas)]"
                } ${focusRing}`}
              >
                {plan.action.label}
              </a>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}
styles/neat-paper.css
/* Neat Labs theme "paper" (revision 9e029aa69c45) for pricing-tiers (revision 1244e13abde7), catalogue 0.1.0. */
:root {
  --nl-canvas: #F5F1E8;
  --nl-surface: #FFFDF8;
  --nl-ink: #1F1B16;
  --nl-muted: #5E554A;
  --nl-line: #D9D0C1;
  --nl-accent: #B4462C;
  --nl-accent-ink: #FFFFFF;
  --nl-focus: #1F5FBF;
  --nl-font-display: "Fraunces", ui-serif, Georgia, serif;
  --nl-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --nl-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --nl-radius: 6px;
  --nl-section-y: 96px;
}

[data-theme="dark"] {
  --nl-canvas: #16130F;
  --nl-surface: #211D18;
  --nl-ink: #F2ECE1;
  --nl-muted: #B3A999;
  --nl-line: #3A342C;
  --nl-accent: #E07A5F;
  --nl-accent-ink: #1A0F0B;
  --nl-focus: #8AB4F8;
}
MCP tool call
{
  "name": "get_component",
  "arguments": {
    "id": "pricing-tiers",
    "style": "paper"
  }
}

In every style