Pricing Comparison Matrix
Detailed SaaS pricing table with feature checkboxes and plan switcher.
pricingmatrixcomparisontogglesaas
Live Preview
Flexible Plans
Transparent Pricing for High-Growth Teams
Choose the right plan to scale your digital products. No hidden fees, cancel anytime.
MonthlyAnnual Save 20%
- โ Up to 3 React Projects
- โ All 200+ UI Components
- โ Community Discord Support
- โ Private Component Registry
- โ Dedicated Priority Support
Most Popular
- โ Unlimited React Projects
- โ All 200+ UI & 3D Components
- โ Figma UI Kit & Design Tokens
- โ Private NPM Team Access
- โ Priority Email & Chat Support
- โ Everything in Pro Plan
- โ Custom Component Engineering
- โ 99.99% Guaranteed SLA
- โ Dedicated Security Audit Support
- โ Dedicated Account Manager
30-Day unconditional money-back guarantee. No questions asked.
Usage
Copy and paste this code into your React component:
tsx
import { PricingComparisonMatrix } from 'react-component-kit-ui/sections';
<PricingComparisonMatrix />Manual Installation
If you are not using the npm package, create a new file and paste the following code: src/components/sections/PricingComparisonMatrix.tsx + PricingComparisonMatrix.css:
PricingComparisonMatrix.tsx
'use client';
import { useEffect, useRef } from 'react';
import './PricingComparisonMatrix.css';
/**
* PricingComparisonMatrix โ Full-page interactive pricing matrix with billing toggle and feature comparison.
*
* @param {string} badge - Eyebrow badge text.
* @param {string} title - Section main heading.
* @param {string} subtitle - Supporting description text.
*/
export interface PricingComparisonMatrixProps {
badge?: string;
title?: string;
subtitle?: string;
className?: string;
}
export function PricingComparisonMatrix({
badge = "Flexible Plans",
title = "Transparent Pricing for High-Growth Teams",
subtitle = "Choose the right plan to scale your digital products. No hidden fees, cancel anytime.",
className = ""
}: PricingComparisonMatrixProps) {
// Ported from the Astro <script>: runs once after mount (DOM logic kept as in the Astro kit).
const mounted = useRef(false);
useEffect(() => {
if (mounted.current) return;
mounted.current = true;
const toggleBtn = document.getElementById('billingToggleBtn');
const priceVals = document.querySelectorAll('.price-val');
if (toggleBtn) {
toggleBtn.addEventListener('click', () => {
const isAnnual = toggleBtn.getAttribute('aria-checked') === 'true';
const newState = !isAnnual;
toggleBtn.setAttribute('aria-checked', String(newState));
priceVals.forEach((el) => {
const val = newState ? el.getAttribute('data-annual') : el.getAttribute('data-monthly');
if (val) el.textContent = val;
});
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<>
<div className="cq-pricing-comparison-matrix-cq" data-rk-4ae18a="">
<section className={`pricing-section ${className}`} aria-labelledby="pricing-title" data-rk-4ae18a="">
<div className="pricing-bg" aria-hidden="true" data-rk-4ae18a="">
<div className="pricing-glow" data-rk-4ae18a=""></div>
</div>
<div className="container" data-rk-4ae18a="">
{/* Header */}
<div className="section-header" data-rk-4ae18a="">
{badge && <span className="section-badge" data-rk-4ae18a="">{badge}</span>}
<h2 id="pricing-title" className="section-title" data-rk-4ae18a="">{title}</h2>
<p className="section-subtitle" data-rk-4ae18a="">{subtitle}</p>
{/* Interactive Billing Toggle */}
<div className="billing-toggle-wrap" data-rk-4ae18a="">
<span className="toggle-label" id="label-monthly" data-rk-4ae18a="">Monthly</span>
<button type="button" className="billing-toggle" id="billingToggleBtn" role="switch" aria-checked="false" aria-label="Toggle annual billing" data-rk-4ae18a="">
<span className="toggle-slider" data-rk-4ae18a=""></span>
</button>
<span className="toggle-label" id="label-annual" data-rk-4ae18a="">
Annual <span className="discount-pill" data-rk-4ae18a="">Save 20%</span>
</span>
</div>
</div>
{/* Pricing Cards Grid */}
<div className="pricing-cards" data-rk-4ae18a="">
{/* 1. Starter Tier */}
<div className="plan-card" data-rk-4ae18a="">
<div className="plan-card__header" data-rk-4ae18a="">
<span className="plan-name" data-rk-4ae18a="">Starter</span>
<p className="plan-desc" data-rk-4ae18a="">For indie developers and personal experiments.</p>
<div className="plan-price" data-rk-4ae18a="">
<span className="price-currency" data-rk-4ae18a="">$</span>
<span className="price-val" data-monthly="19" data-annual="15" data-rk-4ae18a="">19</span>
<span className="price-period" data-rk-4ae18a="">/mo</span>
</div>
<a href="#get-started" className="plan-btn plan-btn--ghost" data-rk-4ae18a="">Get Started</a>
</div>
<div className="plan-divider" data-rk-4ae18a=""></div>
<ul className="plan-features" aria-label="Starter Plan Features" data-rk-4ae18a="">
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Up to 3 React Projects</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> All 200+ UI Components</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Community Discord Support</li>
<li className="feature-disabled" data-rk-4ae18a=""><span className="cross-icon" data-rk-4ae18a="">โ</span> Private Component Registry</li>
<li className="feature-disabled" data-rk-4ae18a=""><span className="cross-icon" data-rk-4ae18a="">โ</span> Dedicated Priority Support</li>
</ul>
</div>
{/* 2. Pro Tier (Featured / Most Popular) */}
<div className="plan-card plan-card--popular" data-rk-4ae18a="">
<div className="popular-ribbon" data-rk-4ae18a="">Most Popular</div>
<div className="plan-card__header" data-rk-4ae18a="">
<span className="plan-name plan-name--popular" data-rk-4ae18a="">Professional</span>
<p className="plan-desc" data-rk-4ae18a="">For fast-moving teams and production web applications.</p>
<div className="plan-price" data-rk-4ae18a="">
<span className="price-currency" data-rk-4ae18a="">$</span>
<span className="price-val" data-monthly="49" data-annual="39" data-rk-4ae18a="">49</span>
<span className="price-period" data-rk-4ae18a="">/mo</span>
</div>
<a href="#get-pro" className="plan-btn plan-btn--primary" data-rk-4ae18a="">Start 14-Day Free Trial</a>
</div>
<div className="plan-divider" data-rk-4ae18a=""></div>
<ul className="plan-features" aria-label="Professional Plan Features" data-rk-4ae18a="">
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Unlimited React Projects</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> All 200+ UI & 3D Components</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Figma UI Kit & Design Tokens</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Private NPM Team Access</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Priority Email & Chat Support</li>
</ul>
</div>
{/* 3. Enterprise Tier */}
<div className="plan-card" data-rk-4ae18a="">
<div className="plan-card__header" data-rk-4ae18a="">
<span className="plan-name" data-rk-4ae18a="">Enterprise</span>
<p className="plan-desc" data-rk-4ae18a="">For organizations requiring custom SLAs and bespoke design systems.</p>
<div className="plan-price" data-rk-4ae18a="">
<span className="price-currency" data-rk-4ae18a="">$</span>
<span className="price-val" data-monthly="149" data-annual="119" data-rk-4ae18a="">149</span>
<span className="price-period" data-rk-4ae18a="">/mo</span>
</div>
<a href="#contact-sales" className="plan-btn plan-btn--ghost" data-rk-4ae18a="">Contact Sales</a>
</div>
<div className="plan-divider" data-rk-4ae18a=""></div>
<ul className="plan-features" aria-label="Enterprise Plan Features" data-rk-4ae18a="">
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Everything in Pro Plan</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Custom Component Engineering</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> 99.99% Guaranteed SLA</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Dedicated Security Audit Support</li>
<li data-rk-4ae18a=""><span className="check-icon" data-rk-4ae18a="">โ</span> Dedicated Account Manager</li>
</ul>
</div>
</div>
{/* Money-back guarantee footer note */}
<div className="pricing-footer" data-rk-4ae18a="">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="guarantee-icon" data-rk-4ae18a=""><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10" data-rk-4ae18a="" /><path d="m9 12 2 2 4-4" data-rk-4ae18a="" /></svg>
<span data-rk-4ae18a="">30-Day unconditional money-back guarantee. No questions asked.</span>
</div>
</div>
</section>
</div>
</>
);
}
export default PricingComparisonMatrix;PricingComparisonMatrix.css
/* PricingComparisonMatrix โ ported from astro-component-kit (sections/PricingComparisonMatrix.astro) */
.cq-pricing-comparison-matrix-cq:where([data-rk-4ae18a]) { container-type: inline-size; }
.pricing-section:where([data-rk-4ae18a]) {
position: relative;
padding: var(--sp-20, 5rem) var(--sp-6, 1.5rem);
background: var(--c-bg-primary, #030712);
overflow: hidden;
}
.pricing-bg:where([data-rk-4ae18a]) {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
}
.pricing-glow:where([data-rk-4ae18a]) {
position: absolute;
top: 20%;
left: 50%;
transform: translateX(-50%);
width: 600px;
height: 500px;
background: radial-gradient(circle, color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent), transparent 70%);
filter: blur(100px);
}
.container:where([data-rk-4ae18a]) {
position: relative;
z-index: 1;
max-width: 1200px;
margin: 0 auto;
}
.section-header:where([data-rk-4ae18a]) {
text-align: center;
max-width: 760px;
margin: 0 auto var(--sp-12, 3rem);
}
.section-badge:where([data-rk-4ae18a]) {
display: inline-flex;
padding: 0.35rem 0.9rem;
border-radius: 9999px;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
background: color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent);
color: #eab308;
border: 1px solid rgba(234, 179, 8, 0.25);
margin-bottom: var(--sp-4, 1rem);
}
.section-title:where([data-rk-4ae18a]) {
font-size: clamp(2rem, 4vw, 3rem);
font-weight: 900;
color: #fff;
line-height: 1.15;
letter-spacing: -0.02em;
margin: 0 0 var(--sp-4, 1rem);
}
.section-subtitle:where([data-rk-4ae18a]) {
font-size: 1.1rem;
color: #94a3b8;
line-height: 1.6;
margin: 0 0 2rem;
}
/* Billing Toggle */
.billing-toggle-wrap:where([data-rk-4ae18a]) {
display: inline-flex;
align-items: center;
gap: 0.75rem;
padding: 0.4rem 0.8rem;
background: rgba(15, 23, 42, 0.8);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
border-radius: 9999px;
}
.toggle-label:where([data-rk-4ae18a]) {
font-size: 0.88rem;
font-weight: 600;
color: #cbd5e1;
}
.discount-pill:where([data-rk-4ae18a]) {
padding: 0.15rem 0.5rem;
background: rgba(16, 185, 129, 0.15);
color: #34d399;
border: 1px solid rgba(16, 185, 129, 0.3);
border-radius: 9999px;
font-size: 0.72rem;
font-weight: 700;
}
.billing-toggle:where([data-rk-4ae18a]) {
width: 44px;
height: 24px;
border-radius: 9999px;
background: rgb(var(--ink-rgb, 255 255 255) / 0.15);
border: none;
position: relative;
cursor: pointer;
padding: 2px;
transition: background 0.3s ease;
}
.toggle-slider:where([data-rk-4ae18a]) {
display: block;
width: 20px;
height: 20px;
border-radius: 50%;
background: #fff;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.billing-toggle[aria-checked="true"]:where([data-rk-4ae18a]) {
background: #eab308;
}
.billing-toggle[aria-checked="true"]:where([data-rk-4ae18a]) .toggle-slider:where([data-rk-4ae18a]) {
transform: translateX(20px);
}
/* Pricing Cards */
.pricing-cards:where([data-rk-4ae18a]) {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
align-items: stretch;
}
.plan-card:where([data-rk-4ae18a]) {
position: relative;
background: rgba(15, 23, 42, 0.6);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
border-radius: var(--r-xl, 20px);
padding: 2.25rem 2rem;
display: flex;
flex-direction: column;
justify-content: space-between;
transition: transform 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}
.plan-card:hover:where([data-rk-4ae18a]) {
transform: translateY(-4px);
border-color: rgb(var(--ink-rgb, 255 255 255) / 0.18);
}
.plan-card--popular:where([data-rk-4ae18a]) {
background: rgba(20, 25, 45, 0.85);
border-color: rgba(234, 179, 8, 0.4);
box-shadow: 0 0 30px -10px rgba(234, 179, 8, 0.25);
transform: scale(1.03);
}
.plan-card--popular:hover:where([data-rk-4ae18a]) {
transform: scale(1.03) translateY(-4px);
}
.popular-ribbon:where([data-rk-4ae18a]) {
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
padding: 0.25rem 0.85rem;
background: linear-gradient(135deg, #eab308, #ca8a04);
color: #000;
font-weight: 800;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.05em;
border-radius: 9999px;
box-shadow: 0 4px 12px rgba(234, 179, 8, 0.4);
}
.plan-name:where([data-rk-4ae18a]) {
font-size: 1.25rem;
font-weight: 800;
color: #fff;
}
.plan-name--popular:where([data-rk-4ae18a]) {
color: #facc15;
}
.plan-desc:where([data-rk-4ae18a]) {
font-size: 0.88rem;
color: #94a3b8;
line-height: 1.5;
margin: 0.4rem 0 1.5rem;
min-height: 40px;
}
.plan-price:where([data-rk-4ae18a]) {
display: flex;
align-items: baseline;
gap: 0.2rem;
margin-bottom: 1.5rem;
}
.price-currency:where([data-rk-4ae18a]) {
font-size: 1.5rem;
font-weight: 700;
color: #94a3b8;
}
.price-val:where([data-rk-4ae18a]) {
font-size: 3rem;
font-weight: 900;
color: #fff;
line-height: 1;
}
.price-period:where([data-rk-4ae18a]) {
font-size: 0.9rem;
color: #64748b;
}
.plan-btn:where([data-rk-4ae18a]) {
display: block;
text-align: center;
padding: 0.85rem 1.5rem;
border-radius: var(--r-md, 10px);
font-size: 0.95rem;
font-weight: 700;
text-decoration: none;
transition: all 0.25s ease;
}
.plan-btn--primary:where([data-rk-4ae18a]) {
background: linear-gradient(135deg, #eab308, #d97706);
color: #000;
box-shadow: 0 4px 15px rgba(234, 179, 8, 0.3);
}
.plan-btn--primary:hover:where([data-rk-4ae18a]) {
filter: brightness(1.1);
box-shadow: 0 6px 20px rgba(234, 179, 8, 0.45);
}
.plan-btn--ghost:where([data-rk-4ae18a]) {
background: rgb(var(--ink-rgb, 255 255 255) / 0.05);
color: #fff;
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.12);
}
.plan-btn--ghost:hover:where([data-rk-4ae18a]) {
background: rgb(var(--ink-rgb, 255 255 255) / 0.1);
border-color: rgb(var(--ink-rgb, 255 255 255) / 0.25);
}
.plan-divider:where([data-rk-4ae18a]) {
height: 1px;
background: rgb(var(--ink-rgb, 255 255 255) / 0.08);
margin: 1.5rem 0;
}
.plan-features:where([data-rk-4ae18a]) {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.85rem;
}
.plan-features:where([data-rk-4ae18a]) li:where([data-rk-4ae18a]) {
display: flex;
align-items: center;
gap: 0.65rem;
font-size: 0.88rem;
color: #cbd5e1;
}
.check-icon:where([data-rk-4ae18a]) {
color: #10b981;
font-weight: 900;
}
.cross-icon:where([data-rk-4ae18a]) {
color: #64748b;
font-weight: 700;
}
.feature-disabled:where([data-rk-4ae18a]) {
color: #64748b;
}
.pricing-footer:where([data-rk-4ae18a]) {
display: flex;
align-items: center;
justify-content: center;
gap: 0.6rem;
margin-top: 3rem;
color: #94a3b8;
font-size: 0.9rem;
}
.guarantee-icon:where([data-rk-4ae18a]) {
color: #10b981;
}
@container (max-width: 960px) {
.pricing-cards:where([data-rk-4ae18a]) {
grid-template-columns: 1fr;
}
.plan-card--popular:where([data-rk-4ae18a]) {
transform: none;
}
.plan-card--popular:hover:where([data-rk-4ae18a]) {
transform: translateY(-4px);
}
}