Feature Comparison

A comprehensive feature comparison table for comparing plans, products, or services. Perfect for pricing pages, product comparisons, and SaaS landing pages.

Comparison GridFeature CategoriesHighlight PopularCTA Buttons

Installation

Terminal
ReactTailwind
TSX
npx @uiblox/cli add feature-comparison

Preview

Layout:

Compare

Starter

$9/mo

Popular

Pro

$29/mo

Enterprise

$99/mo

Projects
5
Unlimited
Unlimited
Storage
10GB
100GB
Unlimited
API Access
Priority support

Use Cases

SaaS Pricing Pages

Help customers choose the right plan by comparing features across tiers.

Product Comparisons

Compare different products, versions, or editions side by side.

Service Packages

Display different service levels and what's included in each.

Tool Comparisons

Compare your product against competitors with feature matrices.

Source Code

feature-comparison.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"use client"; import { useState } from "react"; import { cn } from "@/lib/utils"; interface Plan { name: string; price: string; description: string; popular?: boolean; } interface Feature { name: string; category: string; plans: { [key: string]: boolean | string }; } const plans: Plan[] = [ { name: "Starter", price: "$9", description: "For individuals" }, { name: "Pro", price: "$29", description: "For teams", popular: true }, { name: "Enterprise", price: "$99", description: "For organizations" }, ]; const features: Feature[] = [ { name: "Projects", category: "Core Features", plans: { Starter: "5", Pro: "Unlimited", Enterprise: "Unlimited" } }, { name: "Storage", category: "Core Features", plans: { Starter: "10GB", Pro: "100GB", Enterprise: "Unlimited" } }, { name: "Team members", category: "Core Features", plans: { Starter: "1", Pro: "10", Enterprise: "Unlimited" } }, { name: "API Access", category: "Developer", plans: { Starter: false, Pro: true, Enterprise: true } }, { name: "Webhooks", category: "Developer", plans: { Starter: false, Pro: true, Enterprise: true } }, { name: "Custom integrations", category: "Developer", plans: { Starter: false, Pro: false, Enterprise: true } }, { name: "Basic analytics", category: "Analytics", plans: { Starter: true, Pro: true, Enterprise: true } }, { name: "Advanced reports", category: "Analytics", plans: { Starter: false, Pro: true, Enterprise: true } }, { name: "Custom dashboards", category: "Analytics", plans: { Starter: false, Pro: false, Enterprise: true } }, { name: "Email support", category: "Support", plans: { Starter: true, Pro: true, Enterprise: true } }, { name: "Priority support", category: "Support", plans: { Starter: false, Pro: true, Enterprise: true } }, { name: "Dedicated manager", category: "Support", plans: { Starter: false, Pro: false, Enterprise: true } }, ]; export function FeatureComparison() { const categories = [...new Set(features.map(f => f.category))]; return ( <div className="bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-slate-800 overflow-hidden"> {/* Header */} <div className="grid grid-cols-4 border-b border-slate-200 dark:border-slate-800"> <div className="p-6 bg-slate-50 dark:bg-slate-800/50"> <h2 className="text-lg font-semibold text-slate-900 dark:text-white">Compare Plans</h2> <p className="text-sm text-slate-500 mt-1">Find the perfect plan for your needs</p> </div> {plans.map((plan) => ( <div key={plan.name} className={cn("p-6 text-center", plan.popular && "bg-purple-50 dark:bg-purple-900/10")}> {plan.popular && ( <span className="inline-block px-2 py-0.5 bg-purple-600 text-white text-xs font-medium rounded-full mb-2">Popular</span> )} <h3 className="text-lg font-bold text-slate-900 dark:text-white">{plan.name}</h3> <p className="text-2xl font-bold text-slate-900 dark:text-white mt-1">{plan.price}<span className="text-sm font-normal text-slate-500">/mo</span></p> <p className="text-sm text-slate-500 mt-1">{plan.description}</p> </div> ))} </div> {/* Features */} {categories.map((category) => ( <div key={category}> <div className="px-6 py-3 bg-slate-50 dark:bg-slate-800/50 border-b border-slate-200 dark:border-slate-800"> <h4 className="text-sm font-semibold text-slate-700 dark:text-slate-300">{category}</h4> </div> {features.filter(f => f.category === category).map((feature) => ( <div key={feature.name} className="grid grid-cols-4 border-b border-slate-100 dark:border-slate-800 hover:bg-slate-50 dark:hover:bg-slate-800/30"> <div className="p-4 text-sm text-slate-600 dark:text-slate-400">{feature.name}</div> {plans.map((plan) => { const value = feature.plans[plan.name]; return ( <div key={plan.name} className={cn("p-4 text-center", plan.popular && "bg-purple-50/50 dark:bg-purple-900/5")}> {typeof value === "boolean" ? ( value ? <CheckIcon className="mx-auto text-emerald-500" /> : <XIcon className="mx-auto text-slate-300 dark:text-slate-600" /> ) : ( <span className="text-sm font-medium text-slate-900 dark:text-white">{value}</span> )} </div> ); })} </div> ))} </div> ))} {/* CTA */} <div className="grid grid-cols-4 border-t border-slate-200 dark:border-slate-800"> <div className="p-6"></div> {plans.map((plan) => ( <div key={plan.name} className={cn("p-6 text-center", plan.popular && "bg-purple-50 dark:bg-purple-900/10")}> <button className={cn( "w-full py-2.5 rounded-xl font-semibold transition-colors", plan.popular ? "bg-purple-600 hover:bg-purple-700 text-white" : "bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700 text-slate-900 dark:text-white" )}> Get Started </button> </div> ))} </div> </div> ); } function CheckIcon({ className }: { className?: string }) { return <svg className={cn("w-5 h-5", className)} fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /></svg>; } function XIcon({ className }: { className?: string }) { return <svg className={cn("w-5 h-5", className)} fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>; }