UI Components Easy
Pricing Table
Pricing table with monthly/yearly toggle (20% discount), 3-tier cards, feature comparison list, popular badge, and CTA buttons. Pure CSS + JS.
Open in Lab
MCP
css vanilla-js
Targets: JS HTML
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #0f1117;
--surface: #16181f;
--surface2: #1e2130;
--border: #2a2d3a;
--text: #e2e8f0;
--text-muted: #64748b;
--accent: #818cf8;
--accent-hover: #a5b4fc;
--green: #34d399;
--red: #f87171;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
}
.pricing-page {
max-width: 1100px;
margin: 0 auto;
padding: 60px 24px;
}
.pricing-header {
text-align: center;
margin-bottom: 48px;
}
.pricing-header h1 {
font-size: 2rem;
font-weight: 800;
margin-bottom: 10px;
}
.pricing-header > p {
color: var(--text-muted);
font-size: 1rem;
margin-bottom: 28px;
}
/* Toggle */
.billing-toggle {
display: inline-flex;
align-items: center;
gap: 12px;
}
.toggle-label {
font-size: 0.875rem;
font-weight: 500;
color: var(--text-muted);
}
.toggle-switch {
position: relative;
cursor: pointer;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
position: absolute;
}
.toggle-track {
display: block;
width: 44px;
height: 24px;
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 12px;
position: relative;
transition: border-color .2s;
}
.toggle-switch input:checked ~ .toggle-track {
border-color: var(--accent);
}
.toggle-thumb {
position: absolute;
top: 3px;
left: 3px;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--text-muted);
transition: left .2s, background .2s;
}
.toggle-switch input:checked ~ .toggle-track .toggle-thumb {
left: 23px;
background: var(--accent);
}
.save-badge {
display: inline-block;
background: rgba(52, 211, 153, 0.15);
color: var(--green);
font-size: 0.68rem;
font-weight: 700;
padding: 2px 8px;
border-radius: 999px;
margin-left: 6px;
border: 1px solid rgba(52, 211, 153, 0.2);
}
/* Grid */
.pricing-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
align-items: start;
}
/* Card */
.plan-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 28px;
position: relative;
transition: border-color .2s;
}
.plan-card:hover {
border-color: #3a3d4e;
}
.plan-card--featured {
background: linear-gradient(160deg, #1a1c30, #16181f);
border-color: rgba(129, 140, 248, 0.35);
}
.plan-card--featured:hover {
border-color: var(--accent);
}
.popular-badge {
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(90deg, #818cf8, #a5b4fc);
color: #0f1117;
font-size: 0.72rem;
font-weight: 800;
padding: 4px 14px;
border-radius: 999px;
white-space: nowrap;
}
.plan-name {
font-size: 0.9rem;
font-weight: 700;
color: var(--text-muted);
margin-bottom: 14px;
text-transform: uppercase;
letter-spacing: .08em;
}
.plan-price-wrap {
display: flex;
align-items: flex-end;
gap: 2px;
margin-bottom: 12px;
}
.plan-currency {
font-size: 1.2rem;
font-weight: 700;
color: var(--text-muted);
line-height: 2.2;
}
.plan-price {
font-size: 2.8rem;
font-weight: 800;
line-height: 1;
transition: opacity .2s;
}
.plan-price--custom {
font-size: 1.6rem;
color: var(--text-muted);
}
.plan-period {
font-size: 0.82rem;
color: var(--text-muted);
margin-bottom: 6px;
}
.plan-desc {
font-size: 0.82rem;
color: var(--text-muted);
line-height: 1.6;
margin-bottom: 20px;
}
.plan-cta {
display: block;
text-align: center;
padding: 10px 16px;
border-radius: 9px;
font-size: 0.875rem;
font-weight: 600;
text-decoration: none;
transition: background .15s, opacity .15s;
margin-bottom: 24px;
}
.plan-cta--filled {
background: var(--accent);
color: #fff;
}
.plan-cta--filled:hover {
background: var(--accent-hover);
}
.plan-cta--outline {
border: 1px solid var(--border);
color: var(--text);
background: transparent;
}
.plan-cta--outline:hover {
border-color: var(--accent);
color: var(--accent);
}
.plan-features {
list-style: none;
display: flex;
flex-direction: column;
gap: 10px;
}
.feat {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 0.82rem;
line-height: 1.5;
}
.feat::before {
content: "✓";
font-size: 0.78rem;
font-weight: 700;
flex-shrink: 0;
margin-top: 1px;
}
.feat--yes {
color: var(--text-muted);
}
.feat--yes::before {
color: var(--green);
}
.feat--no {
color: #415168;
text-decoration: line-through;
}
.feat--no::before {
content: "✗";
color: #3d4a5a;
}
@media (max-width: 760px) {
.pricing-grid {
grid-template-columns: 1fr;
}
}const toggle = document.getElementById("billingToggle");
const prices = document.querySelectorAll(".plan-price[data-monthly]");
toggle?.addEventListener("change", () => {
const isYearly = toggle.checked;
prices.forEach((el) => {
const val = isYearly ? el.dataset.yearly : el.dataset.monthly;
el.style.opacity = "0";
setTimeout(() => {
el.textContent = val;
el.style.opacity = "1";
}, 120);
});
});<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pricing Table</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="pricing-page">
<div class="pricing-header">
<h1>Simple, transparent pricing</h1>
<p>Start free. Scale as you grow. No hidden fees.</p>
<!-- Monthly / Yearly toggle -->
<div class="billing-toggle">
<span class="toggle-label" id="monthlyLabel">Monthly</span>
<label class="toggle-switch" aria-label="Switch to yearly billing">
<input type="checkbox" id="billingToggle" />
<span class="toggle-track"><span class="toggle-thumb"></span></span>
</label>
<span class="toggle-label" id="yearlyLabel">
Yearly
<span class="save-badge">Save 20%</span>
</span>
</div>
</div>
<!-- Pricing cards -->
<div class="pricing-grid">
<!-- Free -->
<div class="plan-card">
<div class="plan-name">Free</div>
<div class="plan-price-wrap">
<span class="plan-currency">$</span>
<span class="plan-price" data-monthly="0" data-yearly="0">0</span>
<span class="plan-period">/month</span>
</div>
<p class="plan-desc">Perfect for personal projects and trying out the platform.</p>
<a href="#" class="plan-cta plan-cta--outline">Get started free</a>
<ul class="plan-features">
<li class="feat feat--yes">50 component previews / month</li>
<li class="feat feat--yes">Community access</li>
<li class="feat feat--yes">Basic code export</li>
<li class="feat feat--no">MCP server access</li>
<li class="feat feat--no">Priority support</li>
<li class="feat feat--no">Team collaboration</li>
</ul>
</div>
<!-- Pro (Popular) -->
<div class="plan-card plan-card--featured">
<div class="popular-badge">Most Popular</div>
<div class="plan-name">Pro</div>
<div class="plan-price-wrap">
<span class="plan-currency">$</span>
<span class="plan-price" data-monthly="29" data-yearly="23">29</span>
<span class="plan-period">/month</span>
</div>
<p class="plan-desc">For developers who need the full library and AI tooling.</p>
<a href="#" class="plan-cta plan-cta--filled">Start Pro trial</a>
<ul class="plan-features">
<li class="feat feat--yes">Unlimited component access</li>
<li class="feat feat--yes">Community access</li>
<li class="feat feat--yes">Full code + Figma export</li>
<li class="feat feat--yes">MCP server access</li>
<li class="feat feat--yes">Priority support</li>
<li class="feat feat--no">Team collaboration</li>
</ul>
</div>
<!-- Enterprise -->
<div class="plan-card">
<div class="plan-name">Enterprise</div>
<div class="plan-price-wrap">
<span class="plan-price plan-price--custom">Custom</span>
</div>
<p class="plan-desc">Custom contracts, SLA, dedicated support, and team licenses.</p>
<a href="#" class="plan-cta plan-cta--outline">Contact sales</a>
<ul class="plan-features">
<li class="feat feat--yes">Everything in Pro</li>
<li class="feat feat--yes">Community access</li>
<li class="feat feat--yes">Full code + Figma export</li>
<li class="feat feat--yes">MCP server access</li>
<li class="feat feat--yes">Dedicated support</li>
<li class="feat feat--yes">Team collaboration (unlimited seats)</li>
</ul>
</div>
</div>
</main>
<script src="script.js"></script>
</body>
</html>Pricing Table
A SaaS pricing table with three plans (Free / Pro / Enterprise), monthly/yearly billing toggle with animated price flip and 20% discount display, feature list comparison, a “Most Popular” badge, and CTA buttons.
Features
- Monthly ↔ Yearly toggle (pill switch) — prices animate flip on change
- Three pricing cards: Free, Pro (highlighted), Enterprise
- Feature list per plan with check ✓ / cross ✗ icons
- “Most Popular” gradient badge on the Pro card
- CTA buttons with hover glow effect
- Custom pricing row for Enterprise (“Contact us”)
- Responsive stacking on mobile
How it works
- Toggle updates a
billingvariable;updatePrices()swapsdata-monthly↔data-yearlyattributes on price elements with a CSS flip animation - Card highlight uses
border: 2px solid var(--accent)+box-shadowon the Pro card - Feature rows use Unicode ✓/✗ with CSS color classes