Pricing — 3 Tiers

Three-tier pricing cards with monthly/annual toggle and feature lists.

Pricing buttoncardbadgeseparator

Installation

npx shadcn@latest add @saastro/pricing-01

Preview

Simple, transparent pricing

Choose the plan that fits your needs.

Starter
For personal projects
$0/month
  • 5 blocks
  • Community support
  • MIT license
Popular
Pro
For professional sites
$19/month
  • All blocks
  • Priority support
  • Premium templates
  • Early access
Team
For agencies and teams
$49/month
  • Everything in Pro
  • Team licenses
  • Custom blocks
  • White-label

Source Code

'use client';

import { useState } from 'react';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils';

type Plan = {
  name: string;
  description: string;
  monthlyPrice: number;
  annualPrice: number;
  features: string[];
  popular?: boolean;
  cta: { label: string; href: string };
};

type Pricing01Props = {
  title?: string;
  description?: string;
  plans: Plan[];
  className?: string;
};

function CheckIcon() {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="16"
      height="16"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      className="text-primary"
    >
      <path d="M20 6 9 17l-5-5" />
    </svg>
  );
}

export function Pricing01({ title, description, plans, className }: Pricing01Props) {
  const [annual, setAnnual] = useState(false);

  return (
    <section className={cn('w-full px-6 py-24 md:py-32', className)}>
      <div className="mx-auto max-w-6xl">
        {(title || description) && (
          <div className="mx-auto mb-12 max-w-2xl text-center">
            {title && <h2 className="text-3xl font-bold tracking-tight sm:text-4xl">{title}</h2>}
            {description && <p className="mt-4 text-lg text-muted-foreground">{description}</p>}
          </div>
        )}
        <div className="mb-12 flex justify-center">
          <div className="inline-flex items-center rounded-lg border p-1">
            <button
              onClick={() => setAnnual(false)}
              className={cn(
                'rounded-md px-4 py-2 text-sm font-medium transition-colors',
                !annual
                  ? 'bg-primary text-primary-foreground'
                  : 'text-muted-foreground hover:text-foreground',
              )}
            >
              Monthly
            </button>
            <button
              onClick={() => setAnnual(true)}
              className={cn(
                'rounded-md px-4 py-2 text-sm font-medium transition-colors',
                annual
                  ? 'bg-primary text-primary-foreground'
                  : 'text-muted-foreground hover:text-foreground',
              )}
            >
              Annual
            </button>
          </div>
        </div>
        <div className="grid gap-6 lg:grid-cols-3">
          {plans.map((plan) => (
            <Card
              key={plan.name}
              className={cn('relative flex flex-col', plan.popular && 'border-primary shadow-lg')}
            >
              {plan.popular && (
                <Badge className="absolute -top-3 left-1/2 -translate-x-1/2">Popular</Badge>
              )}
              <CardHeader>
                <CardTitle>{plan.name}</CardTitle>
                <CardDescription>{plan.description}</CardDescription>
                <div className="mt-4">
                  <span className="text-4xl font-bold">
                    ${annual ? plan.annualPrice : plan.monthlyPrice}
                  </span>
                  <span className="text-muted-foreground">/month</span>
                </div>
              </CardHeader>
              <Separator />
              <CardContent className="flex-1 pt-6">
                <ul className="space-y-3">
                  {plan.features.map((feature) => (
                    <li key={feature} className="flex items-center gap-3">
                      <CheckIcon />
                      <span className="text-sm">{feature}</span>
                    </li>
                  ))}
                </ul>
              </CardContent>
              <CardFooter>
                <Button className="w-full" variant={plan.popular ? 'default' : 'outline'} asChild>
                  <a href={plan.cta.href}>{plan.cta.label}</a>
                </Button>
              </CardFooter>
            </Card>
          ))}
        </div>
      </div>
    </section>
  );
}

Registry Setup

Add the Saastro registry to your components.json:

{
  "registries": {
    "@saastro": "https://ui.saastro.io/r/{name}.json"
  }
}