Pricing — 3 Tiers
Three-tier pricing cards with monthly/annual toggle and feature lists.
Pricing buttoncardbadgeseparator
Installation
npx shadcn@latest add @saastro/pricing-01Preview
Simple, transparent pricing
Choose the plan that fits your needs.
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"
}
}