DHxWhy

Two-Plan Diff Pricing Comparison Table

Pricing 6

About

Two-plan diff pricing comparison table for React and Tailwind CSS (shadcn/ui) that compares any two plans and shows only the rows that change, with color-coded upgrades and downgrades. It is built to help people decide on an upgrade in seconds instead of scanning a full feature matrix. Pick plans A and B from the chips, swap them, and read a summary of the price difference with upgrade and downgrade counts; shared rows stay collapsed until you expand them. Values are compared automatically for numbers, "Unlimited", booleans, and leading quantities, with an optional rank order for words and a lower-is-better flag for limits. Rows glide between the gain, lose, and same sections with a FLIP transition, and chart tokens tint the A/B chips and verdict cells. Supports controlled pair and visibility state, choose-plan callbacks, keyboard use, live-region summaries, reduced motion, and light and dark themes. Use it for SaaS pricing pages, upgrade dialogs, and in-app plan pickers. The included demo tours three sample pairs; the component makes no requests. Requires React and lucide-react, with no animation library.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Two-Plan Diff Pricing Comparison Table to your project and fits it to your theme.

Code

How Two-Plan Diff Pricing Comparison Table is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import * as React from "react";
import { TwoPlanDiffPricingTable } from "@/components/ui/two-plan-diff-pricing-table";
import type { DiffGroup, DiffPair, DiffPlan } from "@/components/ui/two-plan-diff-pricing-table";

export const DIFF_PLANS: DiffPlan[] = [
  { id: "starter", name: "Starter", price: 0, actionLabel: "Switch to Starter" },
  { id: "pro", name: "Pro", price: 19, badge: "Popular", actionLabel: "Switch to Pro" },
  { id: "business", name: "Business", price: 49, actionLabel: "Switch to Business" },
  { id: "enterprise", name: "Enterprise", price: 99, actionLabel: "Talk to sales" },
];

export const DIFF_GROUPS: DiffGroup[] = [
  { id: "workspace", label: "Workspace", features: [
    { id: "projects", label: "Projects", values: { starter: "3", pro: "Unlimited", business: "Unlimited", enterprise: "Unlimited" } },
    { id: "members", label: "Team members", values: { starter: "1", pro: "10", business: "50", enterprise: "Unlimited" } },
    { id: "storage", label: "File storage", values: { starter: "5 GB", pro: "100 GB", business: "500 GB", enterprise: "2,000 GB" } },
  ] },
  { id: "workflow", label: "Workflow", features: [
    { id: "automations", label: "Automations", values: { starter: false, pro: true, business: true, enterprise: true } },
    { id: "support", label: "Support", values: { starter: "Community", pro: "Email", business: "Priority", enterprise: "Dedicated" }, rank: ["Community", "Email", "Priority", "Dedicated"] },
    { id: "export", label: "Export data", values: { starter: true, pro: true, business: true, enterprise: true } },
  ] },
  { id: "control", label: "Control", features: [
    { id: "sso", label: "SAML SSO", values: { starter: false, pro: false, business: true, enterprise: true } },
    { id: "audit", label: "Audit log retention", values: { starter: "7 days", pro: "30 days", business: "1 year", enterprise: "Unlimited" }, rank: ["7 days", "30 days", "1 year", "Unlimited"] },
    { id: "seats", label: "Minimum seats", values: { starter: 1, pro: 1, business: 5, enterprise: 25 }, better: "lower" },
    { id: "two-factor", label: "Two-factor auth", values: { starter: true, pro: true, business: true, enterprise: true } },
  ] },
];

const TOUR: DiffPair[] = [["starter", "pro"], ["pro", "business"], ["business", "enterprise"]];

type DemoProps = {
  autoplay?: boolean;
  bare?: boolean;
  controlled?: boolean;
  initialPair?: DiffPair;
  showSame?: boolean;
};

export default function TwoPlanDiffDemo({ autoplay = true, bare = false, controlled = false, initialPair = TOUR[0], showSame = false }: DemoProps) {
  const [pair, setPair] = React.useState(initialPair as DiffPair);
  const [same, setSame] = React.useState(showSame);
  const [choice, setChoice] = React.useState("");
  return (
    <main className="flex min-h-svh w-full items-center justify-center bg-background p-3 text-foreground">
      <div className="w-full max-w-[720px]">
        {!bare && (
          <header className="mb-3 flex items-end justify-between gap-2 px-1">
            <div>
              <p className="mb-1 text-[9px] font-medium uppercase tracking-[0.2em] text-muted-foreground">Compare any two plans</p>
              <h1 className="text-[22px] font-semibold leading-7 tracking-tight">Only the rows that change.</h1>
            </div>
            <span className="mb-1 hidden text-[10px] text-muted-foreground sm:block">Sample plans · billed monthly</span>
          </header>
        )}
        <TwoPlanDiffPricingTable
          plans={DIFF_PLANS}
          groups={DIFF_GROUPS}
          autoplay={autoplay}
          autoplayPairs={TOUR}
          autoplayInterval={2000}
          defaultPair={initialPair}
          defaultShowSame={showSame}
          {...(controlled ? { pair, onPairChange: setPair, showSame: same, onShowSameChange: setSame } : {})}
          onChoosePlan={(plan) => setChoice(plan.name)}
        />
        {choice && <p role="status" data-demo-choice className="sr-only">{choice} selected.</p>}
      </div>
    </main>
  );
}

Dependencies

More by DHxWhy

View all
  • Sun Moon Dark Mode Theme Toggle

    Sun Moon Dark Mode Theme Toggle

    183
  • Country Flags Globe

    Country Flags Globe

    109
  • Live Notification Feed

    Live Notification Feed

    108
  • Airplane Window Gallery

    Airplane Window Gallery

    94
  • Domino Scroll Image Gallery

    Domino Scroll Image Gallery

    93
  • QR Code Scan Login Form with Password Fallback

    QR Code Scan Login Form with Password Fallback

    81
  • Constellation Image Gallery

    Constellation Image Gallery

    79
  • Ferris Wheel Image Gallery

    Ferris Wheel Image Gallery

    71

More in Pricing

View all
  • Pricing Section

    Pricing Section

    578
  • Pricing Section

    Pricing Section

    173
  • Pricing Card

    Pricing Card

    364
  • Single Pricing Card

    Single Pricing Card

    794
  • Pricing Cards

    Pricing Cards

    86
  • Glowing Pricing Tiers

    Glowing Pricing Tiers

    41
  • pricing section

    pricing section

    157
  • Colorful-Pricing

    Colorful-Pricing

    84