Docs/BLOCKS/Comparison Table

Pricing-style comparison table inspired by Claude's subscription page. Supports monthly/annual billing toggle with animated price transitions, a highlighted "Most Popular" column, sticky feature label column on mobile, and per-category row grouping.

Installation#

$ pnpm dlx @gwenui/cli add comparison-table

File Structure#

comparison-table/
├── ComparisonTable.tsx   # ComparisonTable component & demo data
├── index.ts              # Module entry point (re-exports)
└── block.json            # Block metadata configuration

Usage#

Drop in the default table with GwenUI pricing demo data:

import { ComparisonTable } from "@/components/blocks/comparison-table";
 
export default function Page() {
  return <ComparisonTable />;
}

Custom Plans & Features#

Pass your own plans and features:

import { ComparisonTable } from "@/components/blocks/comparison-table";
import type { ComparisonPlan, ComparisonFeature } from "@/components/blocks/comparison-table";
 
const plans: ComparisonPlan[] = [
  { id: "free",  name: "Free",  price: { monthly: 0 } },
  { id: "pro",   name: "Pro",   price: { monthly: 20, annual: 17 }, highlighted: true, badge: "Most Popular" },
  { id: "team",  name: "Team",  price: { monthly: 25, annual: 20 }, badge: "Best Value" },
];
 
const features: ComparisonFeature[] = [
  {
    category: "Usage",
    label: "Messages per day",
    values: { free: "Limited", pro: "5× Free", team: "Pooled" },
  },
  {
    category: "Usage",
    label: "Priority access",
    values: { free: false, pro: true, team: true },
  },
  {
    category: "Features",
    label: "Claude Code",
    values: { free: false, pro: true, team: true },
  },
];
 
export default function Page() {
  return (
    <ComparisonTable
      plans={plans}
      features={features}
      billingToggle
      ctaLabel="Get Started"
      onCtaClick={(planId) => console.log("Selected:", planId)}
    />
  );
}

ComparisonTable Props#

PropTypeDefaultDescription
plansComparisonPlan[]demo dataArray of plan columns.
featuresComparisonFeature[]demo dataArray of feature rows grouped by category.
billingTogglebooleantrueShow monthly/annual billing toggle.
ctaLabelstring"Get Started"CTA button label for all plans.
onCtaClick(planId: string) => voidundefinedCallback when a CTA button is clicked.

ComparisonPlan Props#

PropTypeDefaultDescription
idstringrequiredUnique plan identifier.
namestringrequiredPlan display name.
price{ monthly: number | "Custom", annual?: number | "Custom" }requiredPricing object.
highlightedbooleanfalseAdds orange top border and tinted background.
badgestringundefinedPill badge shown above plan name e.g. "Most Popular".

ComparisonFeature Props#

PropTypeDefaultDescription
categorystringrequiredGroup header label (Space Mono, uppercase).
labelstringrequiredFeature row label.
tooltipstringundefinedInfo tooltip shown on hover.
valuesRecord<string, boolean | string>requiredMap of planId → value. true = check, false = cross, string = custom text.

Layout#

BreakpointBehavior
MobileHorizontal scroll, feature label column sticky left
Tablet+Full table, all columns visible

Dependencies#

PackagePurpose
framer-motionBilling toggle price animation
lucide-reactCheck / X icons, Info tooltip icon
Next.js 16TypeScriptTailwindFramer Motion
Made by JinXSuper with Gwen 🧡