Docs
Pricing Comparison

Pricing Comparison

A modern side-by-side feature comparison table for pricing plans. Clean design with plan cards, feature rows, and responsive layout.

Choose the perfect plan for your team

Compare features across all plans and find the best fit for your needs.

Team members

Number of users included

Basic:
5 users
Pro:
25 users
Enterprise:
Unlimited

Storage

Total storage capacity

Basic:
10 GB
Pro:
100 GB
Enterprise:
Unlimited

API access

Programmatic access to platform

Basic:
Pro:
Enterprise:

Advanced analytics

Detailed insights and reporting

Basic:
Pro:
Enterprise:

Custom integrations

Build your own integrations

Basic:
Pro:
Enterprise:

Priority support

24/7 dedicated support team

Basic:
Pro:
Email
Enterprise:
Phone & Email

SLA guarantee

Uptime service level agreement

Basic:
Pro:
99.9%
Enterprise:
99.99%

SSO & SAML

Single sign-on authentication

Basic:
Pro:
Enterprise:

Audit logs

Complete activity tracking

Basic:
Pro:
30 days
Enterprise:
Unlimited

Custom contracts

Flexible terms and pricing

Basic:
Pro:
Enterprise:

Features

  • Side-by-side comparison - Clear plan comparison layout
  • Plan cards - Beautiful plan headers with pricing
  • Flexible values - Boolean, string, or custom React nodes
  • Highlighted plans - Mark popular or recommended plans
  • Icon support - Add icons to plan cards
  • Feature descriptions - Optional descriptions for each feature
  • Responsive design - Mobile-friendly with plan selector
  • Hover effects - Smooth row highlighting
  • TypeScript support - Full type safety
  • Customizable - Easy to style and extend

Installation

Copy and paste the following code into your project.

import { Check, X, LucideIcon } from "lucide-react";
import { ReactNode } from "react";
 
interface ComparisonFeature {
  name: string;
  description?: string;
  basic: boolean | string | ReactNode;
  pro: boolean | string | ReactNode;
  enterprise: boolean | string | ReactNode;
}
 
interface PricingComparisonProps {
  headline?: string;
  description?: string;
  plans: {
    basic: {
      name: string;
      price: string;
      period?: string;
      description?: string;
      icon?: LucideIcon;
      highlighted?: boolean;
    };
    pro: {
      name: string;
      price: string;
      period?: string;
      description?: string;
      icon?: LucideIcon;
      highlighted?: boolean;
    };
    enterprise: {
      name: string;
      price: string;
      period?: string;
      description?: string;
      icon?: LucideIcon;
      highlighted?: boolean;
    };
  };
  features: ComparisonFeature[];
}
 
export function PricingComparison({
  headline = "Compare plans",
  description,
  plans,
  features,
}: PricingComparisonProps) {
  const renderValue = (value: boolean | string | ReactNode) => {
    if (typeof value === "boolean") {
      return value ? (
        <Check className="h-5 w-5 text-emerald-400" />
      ) : (
        <X className="h-5 w-5 text-zinc-600" />
      );
    }
    return <span className="text-sm font-medium text-white">{value}</span>;
  };
 
  const PlanCard = ({
    plan,
    type,
  }: {
    plan: (typeof plans)[keyof typeof plans];
    type: string;
  }) => {
    const Icon = plan.icon;
    return (
      <div
        className={`relative rounded-2xl border p-6 transition-all ${
          plan.highlighted
            ? "border-blue-500/50 bg-gradient-to-b from-blue-500/10 to-transparent"
            : "border-zinc-800/50 bg-zinc-950"
        }`}
      >
        {plan.highlighted && (
          <div className="absolute -top-3 left-1/2 -translate-x-1/2">
            <span className="rounded-full bg-blue-500 px-3 py-1 text-xs font-semibold text-white">
              Popular
            </span>
          </div>
        )}
        <div className="text-center">
          {Icon && (
            <div className="mb-4 flex justify-center">
              <div className="rounded-lg bg-blue-500/10 p-3">
                <Icon className="h-6 w-6 text-blue-400" />
              </div>
            </div>
          )}
          <h3 className="text-xl font-bold text-white">{plan.name}</h3>
          {plan.description && (
            <p className="mt-2 text-sm text-zinc-500">{plan.description}</p>
          )}
          <div className="mt-4">
            <span className="text-4xl font-bold text-white">{plan.price}</span>
            {plan.period && (
              <span className="ml-2 text-sm text-zinc-500">{plan.period}</span>
            )}
          </div>
        </div>
      </div>
    );
  };
 
  return (
    <section className="w-full bg-black py-12 sm:py-16 lg:py-20 z-30">
      <div className="container px-4 md:px-6">
        <div className="mx-auto max-w-3xl space-y-4 text-center">
          <h2 className="text-3xl font-bold tracking-tighter text-white sm:text-4xl md:text-5xl">
            {headline}
          </h2>
          {description && (
            <p className="text-lg text-zinc-400 md:text-xl">{description}</p>
          )}
        </div>
 
        <div className="mx-auto mt-12 max-w-7xl">
          <div className="hidden lg:grid lg:grid-cols-4 lg:gap-6">
            <div className="p-6" />
            <PlanCard plan={plans.basic} type="basic" />
            <PlanCard plan={plans.pro} type="pro" />
            <PlanCard plan={plans.enterprise} type="enterprise" />
          </div>
 
          <div className="mt-8 overflow-hidden rounded-2xl border border-zinc-800/50 bg-zinc-950">
            <div className="border-b border-zinc-800/50 p-4 lg:hidden">
              <select className="w-full rounded-lg border border-zinc-800 bg-zinc-900 px-4 py-2 text-white">
                <option>{plans.basic.name}</option>
                <option>{plans.pro.name}</option>
                <option>{plans.enterprise.name}</option>
              </select>
            </div>
 
            <div className="divide-y divide-zinc-800/50">
              {features.map((feature, index) => (
                <div
                  key={index}
                  className="grid grid-cols-1 gap-4 p-6 transition-colors hover:bg-zinc-900/30 lg:grid-cols-4 lg:items-center"
                >
                  <div>
                    <h4 className="font-semibold text-white">{feature.name}</h4>
                    {feature.description && (
                      <p className="mt-1 text-sm text-zinc-500">
                        {feature.description}
                      </p>
                    )}
                  </div>
                  <div className="flex items-center justify-center lg:justify-center">
                    <div className="lg:hidden mr-auto text-sm text-zinc-500">
                      {plans.basic.name}:
                    </div>
                    {renderValue(feature.basic)}
                  </div>
                  <div className="flex items-center justify-center lg:justify-center">
                    <div className="lg:hidden mr-auto text-sm text-zinc-500">
                      {plans.pro.name}:
                    </div>
                    {renderValue(feature.pro)}
                  </div>
                  <div className="flex items-center justify-center lg:justify-center">
                    <div className="lg:hidden mr-auto text-sm text-zinc-500">
                      {plans.enterprise.name}:
                    </div>
                    {renderValue(feature.enterprise)}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

Usage

Basic Usage

import PricingComparison from "@/components/ui/pricing-comparison";
import { Zap, Rocket, Building2 } from "lucide-react";
 
export default function Page() {
  return (
    <PricingComparison
      headline="Compare plans"
      description="Find the perfect plan for your needs."
      plans={{
        basic: {
          name: "Basic",
          price: "$29",
          period: "/month",
          icon: Zap,
        },
        pro: {
          name: "Pro",
          price: "$99",
          period: "/month",
          icon: Rocket,
          highlighted: true,
        },
        enterprise: {
          name: "Enterprise",
          price: "Custom",
          icon: Building2,
        },
      }}
      features={[
        {
          name: "Team members",
          basic: "5 users",
          pro: "25 users",
          enterprise: "Unlimited",
        },
        {
          name: "API access",
          basic: false,
          pro: true,
          enterprise: true,
        },
        {
          name: "Priority support",
          basic: false,
          pro: "Email",
          enterprise: "Phone & Email",
        },
      ]}
    />
  );
}

With Descriptions

<PricingComparison
  headline="Choose your plan"
  plans={{
    basic: {
      name: "Starter",
      price: "$19",
      period: "/month",
      description: "Perfect for individuals",
    },
    pro: {
      name: "Professional",
      price: "$49",
      period: "/month",
      description: "For growing teams",
      highlighted: true,
    },
    enterprise: {
      name: "Enterprise",
      price: "Custom",
      description: "For large organizations",
    },
  }}
  features={[
    {
      name: "Storage",
      description: "Total storage capacity included",
      basic: "10 GB",
      pro: "100 GB",
      enterprise: "Unlimited",
    },
    {
      name: "Advanced analytics",
      description: "Detailed insights and reporting",
      basic: false,
      pro: true,
      enterprise: true,
    },
  ]}
/>

Custom Values

<PricingComparison
  plans={{
    basic: { name: "Basic", price: "$29" },
    pro: { name: "Pro", price: "$99" },
    enterprise: { name: "Enterprise", price: "Custom" },
  }}
  features={[
    {
      name: "Support",
      basic: false,
      pro: <span className="text-yellow-400">Email only</span>,
      enterprise: (
        <div className="flex items-center gap-2">
          <span className="text-emerald-400">24/7 Phone</span>
        </div>
      ),
    },
  ]}
/>

Props

PricingComparisonProps

PropTypeDefaultDescription
headlinestring"Compare plans"Section headline
descriptionstringundefinedOptional description
plansPlansRequiredPlan configuration object
featuresComparisonFeature[]RequiredArray of features to compare

Plan Object

PropTypeDefaultDescription
namestringRequiredPlan name
pricestringRequiredPlan price
periodstringundefinedBilling period (e.g., "/month")
descriptionstringundefinedPlan description
iconLucideIconundefinedPlan icon
highlightedbooleanfalseHighlight as popular plan

ComparisonFeature

PropTypeDefaultDescription
namestringRequiredFeature name
descriptionstringundefinedFeature description
basicboolean | string | ReactNodeRequiredValue for basic plan
proboolean | string | ReactNodeRequiredValue for pro plan
enterpriseboolean | string | ReactNodeRequiredValue for enterprise plan

TypeScript Interface

interface PricingComparisonProps {
  headline?: string;
  description?: string;
  plans: {
    basic: PlanConfig;
    pro: PlanConfig;
    enterprise: PlanConfig;
  };
  features: ComparisonFeature[];
}
 
interface PlanConfig {
  name: string;
  price: string;
  period?: string;
  description?: string;
  icon?: LucideIcon;
  highlighted?: boolean;
}
 
interface ComparisonFeature {
  name: string;
  description?: string;
  basic: boolean | string | ReactNode;
  pro: boolean | string | ReactNode;
  enterprise: boolean | string | ReactNode;
}

Value Types

Features support three value types:

  • Boolean: Renders checkmark (✓) or X (✗)
  • String: Displays as text (e.g., "10 GB", "Unlimited")
  • ReactNode: Custom JSX for complex values

Responsive Behavior

  • Desktop (lg+): Side-by-side comparison with plan cards
  • Mobile: Stacked layout with plan selector dropdown

Use Cases

Perfect for:

  • Pricing page comparisons
  • Feature tier displays
  • Product plan differences
  • Service level comparisons
  • Subscription options
  • Package comparisons
  • Membership tiers
  • License comparisons