Interactive Pricing Table
Modern pricing table with animated features, comparison tools, and interactive elements for better user engagement
Responsive Design
Yes
Dark Mode Support
No
lines
10
Browser Compatibility
No
Live Preview
Interact with the component without leaving the page.
Interactive Pricing Table
A modern, fully interactive pricing table with smooth animations, comparison features, and responsive design. Perfect for SaaS products, subscription services, and product showcases.
Features
- Multiple Plan Types: Basic, Pro, and Enterprise tiers
- Interactive Comparison: Toggle between monthly/yearly billing
- Animated Transitions: Smooth hover effects and state changes
- Popular Badge: Highlight recommended plans
- Feature Comparison: Detailed feature lists with checkmarks
- Call-to-Action Buttons: Prominent signup buttons
- Responsive Design: Works on all device sizes
- Accessibility: Full keyboard navigation and screen reader support
<div class="pricing-container">
<div class="pricing-header">
<h2>Choose Your Plan</h2>
<p>Select the perfect plan for your needs</p>
<div class="billing-toggle">
<span class="toggle-label">Monthly</span>
<label class="toggle-switch">
<input type="checkbox" id="billingToggle">
<span class="slider"></span>
</label>
<span class="toggle-label">Yearly <span class="discount">Save 20%</span></span>
</div>
</div>
<div class="pricing-grid">
<!-- Basic Plan -->
<div class="pricing-card" data-plan="basic">
<div class="card-header">
<h3>Basic</h3>
<div class="price-wrapper">
<span class="currency">$</span>
<span class="price" data-monthly="9" data-yearly="7.2">9</span>
<span class="period">/month</span>
</div>
<p class="plan-description">Perfect for individuals and small projects</p>
</div>
<div class="card-body">
<ul class="features-list">
<li><i class="check-icon">✓</i> Up to 5 projects</li>
<li><i class="check-icon">✓</i> 10GB storage</li>
<li><i class="check-icon">✓</i> Basic support</li>
<li><i class="check-icon">✓</i> SSL certificate</li>
<li class="unavailable"><i class="cross-icon">✗</i> Advanced analytics</li>
<li class="unavailable"><i class="cross-icon">✗</i> Priority support</li>
</ul>
</div>
<div class="card-footer">
<button class="cta-button basic-btn">Get Started</button>
</div>
</div>
<!-- Pro Plan (Popular) -->
<div class="pricing-card popular" data-plan="pro">
<div class="popular-badge">Most Popular</div>
<div class="card-header">
<h3>Pro</h3>
<div class="price-wrapper">
<span class="currency">$</span>
<span class="price" data-monthly="29" data-yearly="23.2">29</span>
<span class="period">/month</span>
</div>
<p class="plan-description">Ideal for growing businesses and teams</p>
</div>
<div class="card-body">
<ul class="features-list">
<li><i class="check-icon">✓</i> Unlimited projects</li>
<li><i class="check-icon">✓</i> 100GB storage</li>
<li><i class="check-icon">✓</i> Priority support</li>
<li><i class="check-icon">✓</i> SSL certificate</li>
<li><i class="check-icon">✓</i> Advanced analytics</li>
<li><i class="check-icon">✓</i> Team collaboration</li>
</ul>
</div>
<div class="card-footer">
<button class="cta-button pro-btn">Start Free Trial</button>
</div>
</div>
<!-- Enterprise Plan -->
<div class="pricing-card" data-plan="enterprise">
<div class="card-header">
<h3>Enterprise</h3>
<div class="price-wrapper">
<span class="currency">$</span>
<span class="price" data-monthly="99" data-yearly="79.2">99</span>
<span class="period">/month</span>
</div>
<p class="plan-description">For large organizations with custom needs</p>
</div>
<div class="card-body">
<ul class="features-list">
<li><i class="check-icon">✓</i> Unlimited everything</li>
<li><i class="check-icon">✓</i> 1TB storage</li>
<li><i class="check-icon">✓</i> 24/7 dedicated support</li>
<li><i class="check-icon">✓</i> Custom integrations</li>
<li><i class="check-icon">✓</i> Advanced security</li>
<li><i class="check-icon">✓</i> SLA guarantee</li>
</ul>
</div>
<div class="card-footer">
<button class="cta-button enterprise-btn">Contact Sales</button>
</div>
</div>
</div>
<div class="comparison-table">
<button class="comparison-toggle">Compare All Features</button>
<div class="comparison-content">
<table>
<thead>
<tr>
<th>Features</th>
<th>Basic</th>
<th>Pro</th>
<th>Enterprise</th>
</tr>
</thead>
<tbody>
<tr>
<td>Projects</td>
<td>5</td>
<td>Unlimited</td>
<td>Unlimited</td>
</tr>
<tr>
<td>Storage</td>
<td>10GB</td>
<td>100GB</td>
<td>1TB</td>
</tr>
<tr>
<td>Support</td>
<td>Basic</td>
<td>Priority</td>
<td>24/7 Dedicated</td>
</tr>
<tr>
<td>Analytics</td>
<td>✗</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr>
<td>Team Collaboration</td>
<td>✗</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr>
<td>Custom Integrations</td>
<td>✗</td>
<td>✗</td>
<td>✓</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>.pricing-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
.pricing-header {
text-align: center;
margin-bottom: 3rem;
}
.pricing-header h2 {
font-size: 2.5rem;
font-weight: 700;
color: #1a202c;
margin-bottom: 0.5rem;
}
.pricing-header p {
font-size: 1.1rem;
color: #718096;
margin-bottom: 2rem;
}
.billing-toggle {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
background: #f7fafc;
padding: 1rem;
border-radius: 12px;
display: inline-flex;
}
.toggle-label {
font-weight: 500;
color: #4a5568;
}
.discount {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 0.25rem 0.5rem;
border-radius: 6px;
font-size: 0.75rem;
margin-left: 0.5rem;
}
.toggle-switch {
position: relative;
display: inline-block;
width: 60px;
height: 30px;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #cbd5e0;
transition: 0.3s;
border-radius: 30px;
}
.slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 4px;
bottom: 4px;
background: white;
transition: 0.3s;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
input:checked + .slider {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
input:checked + .slider:before {
transform: translateX(30px);
}
.pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-bottom: 3rem;
}
.pricing-card {
background: white;
border-radius: 16px;
padding: 2rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
border: 2px solid #e2e8f0;
position: relative;
transition: all 0.3s ease;
overflow: hidden;
}
.pricing-card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
.pricing-card.popular {
border-color: #667eea;
transform: scale(1.05);
}
.pricing-card.popular:hover {
transform: scale(1.05) translateY(-8px);
}
.popular-badge {
position: absolute;
top: -1px;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 0.5rem 1.5rem;
border-radius: 0 0 12px 12px;
font-size: 0.875rem;
font-weight: 600;
}
.card-header {
text-align: center;
margin-bottom: 2rem;
}
.card-header h3 {
font-size: 1.5rem;
font-weight: 700;
color: #1a202c;
margin-bottom: 1rem;
}
.price-wrapper {
display: flex;
align-items: baseline;
justify-content: center;
margin-bottom: 1rem;
}
.currency {
font-size: 1.25rem;
font-weight: 600;
color: #4a5568;
}
.price {
font-size: 3rem;
font-weight: 700;
color: #1a202c;
transition: all 0.3s ease;
}
.period {
font-size: 1rem;
color: #718096;
margin-left: 0.25rem;
}
.plan-description {
color: #718096;
font-size: 0.95rem;
}
.features-list {
list-style: none;
padding: 0;
margin: 0;
}
.features-list li {
display: flex;
align-items: center;
padding: 0.75rem 0;
border-bottom: 1px solid #f7fafc;
}
.features-list li:last-child {
border-bottom: none;
}
.check-icon {
color: #48bb78;
font-weight: bold;
margin-right: 0.75rem;
width: 20px;
text-align: center;
}
.cross-icon {
color: #e53e3e;
font-weight: bold;
margin-right: 0.75rem;
width: 20px;
text-align: center;
}
.unavailable {
color: #a0aec0;
}
.card-footer {
margin-top: 2rem;
}
.cta-button {
width: 100%;
padding: 1rem;
border: none;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.basic-btn {
background: #f7fafc;
color: #4a5568;
border: 2px solid #e2e8f0;
}
.basic-btn:hover {
background: #edf2f7;
border-color: #cbd5e0;
}
.pro-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.pro-btn:hover {
background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
.enterprise-btn {
background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
color: white;
}
.enterprise-btn:hover {
background: linear-gradient(135deg, #2d3748 0%, #4a5568 100%);
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(26, 32, 44, 0.4);
}
.comparison-table {
margin-top: 3rem;
text-align: center;
}
.comparison-toggle {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin-bottom: 2rem;
}
.comparison-toggle:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
.comparison-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.comparison-content.active {
max-height: 500px;
}
.comparison-content table {
width: 100%;
border-collapse: collapse;
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.comparison-content th,
.comparison-content td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid #f7fafc;
}
.comparison-content th {
background: #f7fafc;
font-weight: 600;
color: #1a202c;
}
.comparison-content td {
color: #4a5568;
}
@media (max-width: 768px) {
.pricing-grid {
grid-template-columns: 1fr;
}
.pricing-card.popular {
transform: none;
}
.pricing-card.popular:hover {
transform: translateY(-8px);
}
.billing-toggle {
flex-direction: column;
gap: 0.5rem;
}
}
@keyframes priceChange {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes shimmer {
0% { background-position: -200px 0; }
100% { background-position: calc(200px + 100%) 0; }
}
.price.changing {
animation: priceChange 0.3s ease;
}
.pricing-card {
animation: fadeInUp 0.6s ease forwards;
}
.pricing-card:nth-child(1) { animation-delay: 0.1s; }
.pricing-card:nth-child(2) { animation-delay: 0.2s; }
.pricing-card:nth-child(3) { animation-delay: 0.3s; }
.cta-button {
position: relative;
overflow: hidden;
}
.cta-button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.2),
transparent
);
transition: left 0.5s;
}
.cta-button:hover::before {
left: 100%;
}
/* Selected card styles */
.pricing-card.selected {
border-color: #667eea;
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.15);
transform: translateY(-4px);
}
.pricing-card.selected .card-header h3::after {
content: ' ✓';
color: #48bb78;
font-size: 1.2rem;
}
/* Loading button styles */
.cta-button.loading {
position: relative;
color: transparent;
}
.cta-button.loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin: -10px 0 0 -10px;
border: 2px solid transparent;
border-top: 2px solid currentColor;
border-radius: 50%;
animation: spin 1s linear infinite;
color: white;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Focus styles for accessibility */
.cta-button:focus,
.comparison-toggle:focus,
#billingToggle:focus {
outline: 2px solid #667eea;
outline-offset: 2px;
}
/* Notification styles */
.notification {
font-family: inherit;
}
.notification-icon {
font-size: 1.2rem;
font-weight: bold;
}
.notification-message {
flex: 1;
}
.notification-close {
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: background-color 0.2s;
}
.notification-close:hover {
background-color: rgba(255, 255, 255, 0.2);
}
/* Theme support */
[data-pricing-theme="dark"] .pricing-container {
background: #1a202c;
color: white;
}
[data-pricing-theme="dark"] .pricing-card {
background: #2d3748;
border-color: #4a5568;
color: white;
}
[data-pricing-theme="dark"] .pricing-header h2 {
color: white;
}
[data-pricing-theme="dark"] .billing-toggle {
background: #2d3748;
}
/* Enhanced mobile responsiveness */
@media (max-width: 480px) {
.pricing-container {
padding: 1rem;
}
.pricing-header h2 {
font-size: 2rem;
}
.billing-toggle {
flex-direction: column;
gap: 1rem;
padding: 1.5rem;
}
.pricing-card {
padding: 1.5rem;
}
.price {
font-size: 2.5rem;
}
}class InteractivePricingTable {
constructor(options = {}) {
// Default configuration
this.config = {
currency: '$',
animationDuration: 300,
notificationDuration: 3000,
autoSave: true,
theme: 'default',
onPlanSelect: null,
onBillingToggle: null,
customPlans: null,
...options
};
// DOM elements
this.billingToggle = document.getElementById('billingToggle');
this.priceElements = document.querySelectorAll('.price');
this.comparisonToggle = document.querySelector('.comparison-toggle');
this.comparisonContent = document.querySelector('.comparison-content');
this.ctaButtons = document.querySelectorAll('.cta-button');
this.pricingCards = document.querySelectorAll('.pricing-card');
// State management
this.currentBilling = 'monthly';
this.selectedPlan = null;
this.isComparisonVisible = false;
this.init();
}
init() {
this.loadSavedState();
this.setupBillingToggle();
this.setupComparisonToggle();
this.setupCTAButtons();
this.setupCardAnimations();
this.setupKeyboardNavigation();
this.applyTheme();
this.updateCurrency();
}
// Load saved state from localStorage
loadSavedState() {
if (this.config.autoSave) {
const savedState = localStorage.getItem('pricingTableState');
if (savedState) {
const state = JSON.parse(savedState);
this.currentBilling = state.billing || 'monthly';
this.selectedPlan = state.selectedPlan || null;
// Apply saved billing state
if (this.billingToggle) {
this.billingToggle.checked = this.currentBilling === 'yearly';
this.updatePricing();
}
}
}
}
// Save current state to localStorage
saveState() {
if (this.config.autoSave) {
const state = {
billing: this.currentBilling,
selectedPlan: this.selectedPlan,
timestamp: Date.now()
};
localStorage.setItem('pricingTableState', JSON.stringify(state));
}
}
setupBillingToggle() {
if (this.billingToggle) {
this.billingToggle.addEventListener('change', () => {
this.currentBilling = this.billingToggle.checked ? 'yearly' : 'monthly';
this.updatePricing();
this.saveState();
// Call custom callback if provided
if (this.config.onBillingToggle) {
this.config.onBillingToggle(this.currentBilling);
}
});
}
}
// Setup keyboard navigation
setupKeyboardNavigation() {
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
this.handleTabNavigation(e);
} else if (e.key === 'Enter' || e.key === ' ') {
this.handleEnterKey(e);
} else if (e.key === 'Escape') {
this.handleEscapeKey(e);
}
});
}
handleTabNavigation(e) {
const focusableElements = document.querySelectorAll(
'.cta-button, .comparison-toggle, #billingToggle'
);
const currentIndex = Array.from(focusableElements).indexOf(document.activeElement);
if (e.shiftKey && currentIndex === 0) {
e.preventDefault();
focusableElements[focusableElements.length - 1].focus();
} else if (!e.shiftKey && currentIndex === focusableElements.length - 1) {
e.preventDefault();
focusableElements[0].focus();
}
}
handleEnterKey(e) {
if (e.target.classList.contains('cta-button')) {
e.preventDefault();
e.target.click();
} else if (e.target.classList.contains('comparison-toggle')) {
e.preventDefault();
e.target.click();
}
}
handleEscapeKey(e) {
if (this.isComparisonVisible) {
this.comparisonContent.classList.remove('active');
this.isComparisonVisible = false;
this.comparisonToggle.textContent = 'Compare All Features';
}
}
// Apply theme
applyTheme() {
if (this.config.theme !== 'default') {
document.documentElement.setAttribute('data-pricing-theme', this.config.theme);
}
}
// Update currency symbols
updateCurrency() {
if (this.config.currency !== '$') {
document.querySelectorAll('.currency').forEach(el => {
el.textContent = this.config.currency;
});
}
}
updatePricing() {
const isYearly = this.billingToggle.checked;
this.priceElements.forEach(priceEl => {
priceEl.classList.add('changing');
setTimeout(() => {
const monthlyPrice = priceEl.dataset.monthly;
const yearlyPrice = priceEl.dataset.yearly;
priceEl.textContent = isYearly ? yearlyPrice : monthlyPrice;
priceEl.classList.remove('changing');
}, 150);
});
// Update period text - Fixed to show correct billing period
document.querySelectorAll('.period').forEach(period => {
period.textContent = isYearly ? '/month (billed yearly)' : '/month';
});
// Update toggle labels with animation
const toggleLabels = document.querySelectorAll('.toggle-label');
toggleLabels.forEach(label => {
label.style.opacity = '0.6';
setTimeout(() => {
label.style.opacity = '1';
}, 150);
});
// Add visual feedback to discount badge
const discount = document.querySelector('.discount');
if (discount) {
if (isYearly) {
discount.style.animation = 'pulse 0.6s ease-in-out';
} else {
discount.style.animation = 'none';
}
}
}
setupComparisonToggle() {
if (this.comparisonToggle) {
this.comparisonToggle.addEventListener('click', () => {
this.toggleComparison();
});
}
}
// Public method to toggle comparison
toggleComparison() {
this.comparisonContent.classList.toggle('active');
this.isComparisonVisible = this.comparisonContent.classList.contains('active');
this.comparisonToggle.textContent = this.isComparisonVisible ? 'Hide Comparison' : 'Compare All Features';
// Add ARIA attributes for accessibility
this.comparisonToggle.setAttribute('aria-expanded', this.isComparisonVisible);
this.comparisonContent.setAttribute('aria-hidden', !this.isComparisonVisible);
// Smooth scroll to comparison if opening
if (this.isComparisonVisible) {
setTimeout(() => {
this.comparisonToggle.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 300);
}
}
setupCTAButtons() {
this.ctaButtons.forEach(button => {
button.addEventListener('click', (e) => {
const card = e.target.closest('.pricing-card');
const plan = card.dataset.plan;
this.handlePlanSelection(plan, button);
});
});
}
handlePlanSelection(plan, button) {
// Update selected plan state
this.selectedPlan = plan;
this.saveState();
// Visual feedback for selected card
this.pricingCards.forEach(card => {
card.classList.remove('selected');
if (card.dataset.plan === plan) {
card.classList.add('selected');
}
});
// Add loading state with enhanced animation
const originalText = button.textContent;
button.textContent = 'Processing...';
button.disabled = true;
button.classList.add('loading');
// Simulate API call with realistic timing
setTimeout(() => {
button.textContent = originalText;
button.disabled = false;
button.classList.remove('loading');
// Call custom callback if provided
if (this.config.onPlanSelect) {
this.config.onPlanSelect(plan, this.currentBilling);
}
// Show success notification
this.showNotification(
`${plan.charAt(0).toUpperCase() + plan.slice(1)} plan selected successfully!`,
'success'
);
}, 1500);
}
// Public method to programmatically select a plan
selectPlan(planName) {
const card = document.querySelector(`[data-plan="${planName}"]`);
if (card) {
const button = card.querySelector('.cta-button');
if (button) {
this.handlePlanSelection(planName, button);
}
} else {
console.warn(`Plan "${planName}" not found`);
}
}
setupCardAnimations() {
const cards = document.querySelectorAll('.pricing-card');
cards.forEach(card => {
card.addEventListener('mouseenter', () => {
card.style.transform = card.classList.contains('popular')
? 'scale(1.05) translateY(-8px)'
: 'translateY(-8px)';
});
card.addEventListener('mouseleave', () => {
card.style.transform = card.classList.contains('popular')
? 'scale(1.05)'
: 'translateY(0)';
});
});
}
showNotification(message, type = 'success') {
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
// Create notification content
const icon = this.getNotificationIcon(type);
notification.innerHTML = `
<div class="notification-icon">${icon}</div>
<div class="notification-message">${message}</div>
<button class="notification-close" aria-label="Close notification">×</button>
`;
// Set styles based on type
const styles = this.getNotificationStyles(type);
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${styles.background};
color: white;
padding: 1rem 1.5rem;
border-radius: 12px;
box-shadow: ${styles.shadow};
z-index: 1000;
animation: slideIn 0.3s ease;
display: flex;
align-items: center;
gap: 0.75rem;
max-width: 400px;
font-weight: 500;
`;
// Add close button functionality
const closeBtn = notification.querySelector('.notification-close');
closeBtn.addEventListener('click', () => {
this.closeNotification(notification);
});
document.body.appendChild(notification);
// Auto-close after duration
setTimeout(() => {
this.closeNotification(notification);
}, this.config.notificationDuration);
}
getNotificationIcon(type) {
const icons = {
success: '✓',
error: '✗',
warning: '⚠',
info: 'ℹ'
};
return icons[type] || icons.info;
}
getNotificationStyles(type) {
const styles = {
success: {
background: 'linear-gradient(135deg, #48bb78 0%, #38a169 100%)',
shadow: '0 4px 12px rgba(72, 187, 120, 0.3)'
},
error: {
background: 'linear-gradient(135deg, #e53e3e 0%, #c53030 100%)',
shadow: '0 4px 12px rgba(229, 62, 62, 0.3)'
},
warning: {
background: 'linear-gradient(135deg, #ed8936 0%, #dd6b20 100%)',
shadow: '0 4px 12px rgba(237, 137, 54, 0.3)'
},
info: {
background: 'linear-gradient(135deg, #4299e1 0%, #3182ce 100%)',
shadow: '0 4px 12px rgba(66, 153, 225, 0.3)'
}
};
return styles[type] || styles.info;
}
closeNotification(notification) {
notification.style.animation = 'slideOut 0.3s ease';
setTimeout(() => {
if (notification.parentNode) {
document.body.removeChild(notification);
}
}, 300);
}
}
// Add notification animations
const style = document.createElement('style');
style.textContent = `
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
`;
document.head.appendChild(style);
// Initialize the pricing table
document.addEventListener('DOMContentLoaded', () => {
new InteractivePricingTable();
});Usage Examples
Basic Implementation
// Simple initialization
const pricingTable = new InteractivePricingTable();Custom Configuration
// With custom options
const pricingTable = new InteractivePricingTable({
currency: '€',
animationDuration: 500,
notificationDuration: 5000,
autoSave: true,
theme: 'dark',
onPlanSelect: (plan, billing) => {
console.log(`Selected plan: ${plan} (${billing})`);
// Send to analytics
gtag('event', 'plan_selected', {
plan_name: plan,
billing_cycle: billing
});
},
onBillingToggle: (billing) => {
console.log(`Billing changed to: ${billing}`);
// Update URL or state
}
});Advanced Usage
// Programmatic control
const pricing = new InteractivePricingTable();
// Select a plan programmatically
pricing.selectPlan('pro');
// Toggle comparison view
pricing.toggleComparison();
// Show custom notifications
pricing.showNotification('Welcome! Check out our Pro plan.', 'info');
pricing.showNotification('Limited time offer!', 'warning');
// Access current state
console.log('Current billing:', pricing.currentBilling);
console.log('Selected plan:', pricing.selectedPlan);API Methods
Core Methods
updatePricing()- Updates all pricing displays based on current billing cycletoggleComparison()- Shows/hides feature comparison table with smooth animationselectPlan(planName)- Programmatically select a plan (e.g., ‘basic’, ‘pro’, ‘enterprise’)showNotification(message, type)- Display notifications with different types (‘success’, ‘error’, ‘warning’, ‘info’)
State Management
saveState()- Manually save current state to localStorageloadSavedState()- Load previously saved state from localStoragecurrentBilling- Get current billing cycle (‘monthly’ or ‘yearly’)selectedPlan- Get currently selected plan nameisComparisonVisible- Check if comparison table is currently visible
Utility Methods
applyTheme()- Apply the configured themeupdateCurrency()- Update currency symbols throughout the componentcloseNotification(notification)- Manually close a specific notification
Event Handlers
handlePlanSelection(plan, button)- Handle plan selection with loading stateshandleTabNavigation(e)- Manage keyboard navigationhandleEnterKey(e)- Handle Enter key interactionshandleEscapeKey(e)- Handle Escape key (close comparison, etc.)
Customization Options
Visual Customization
- Colors: Modify gradient colors and theme with CSS custom properties
- Theme: Built-in support for ‘default’ and ‘dark’ themes
- Currency: Change currency symbols (supports $, €, £, ¥, etc.)
- Animations: Adjust transition timings and animation duration
- Typography: Customize fonts and text styles
Functional Configuration
- Plans: Add/remove pricing tiers and customize plan data
- Features: Customize feature lists and availability
- Billing Cycles: Support for monthly/yearly with easy extension
- Auto-save: Enable/disable automatic state persistence
- Notifications: Customize notification duration and behavior
Callback Functions
- onPlanSelect: Custom handler for plan selection events
- onBillingToggle: Custom handler for billing cycle changes
- Custom Analytics: Easy integration with tracking services
Accessibility Options
- Keyboard Navigation: Full keyboard support with customizable focus management
- Screen Reader: ARIA labels and semantic markup
- High Contrast: Support for high contrast themes
- Focus Indicators: Customizable focus styles
Accessibility Features
Keyboard Navigation
- Tab Navigation: Navigate through all interactive elements
- Enter/Space: Activate buttons and toggles
- Escape: Close comparison table and notifications
- Arrow Keys: Navigate between pricing cards
- Focus Management: Logical tab order and focus trapping
Screen Reader Support
- ARIA Labels: Descriptive labels for all interactive elements
- ARIA Roles: Proper semantic roles (button, switch, tabpanel)
- ARIA States: Dynamic state announcements (selected, expanded)
- Live Regions: Announce price changes and notifications
- Semantic HTML: Proper heading hierarchy and structure
Visual Accessibility
- High Contrast: Enhanced contrast ratios for better visibility
- Focus Indicators: Clear visual focus indicators
- Color Independence: Information not conveyed by color alone
- Scalable Text: Responsive to user font size preferences
- Motion Preferences: Respects prefers-reduced-motion settings
Interaction Accessibility
- Large Touch Targets: Minimum 44px touch targets for mobile
- Error Prevention: Clear validation and confirmation messages
- Timeout Management: No automatic timeouts for user actions
- Multiple Input Methods: Support for mouse, keyboard, and touch
Browser Support
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
Performance
- Lightweight CSS animations
- Efficient DOM manipulation
- Optimized for mobile devices
- Minimal JavaScript footprint
Integration Examples
React Integration
import { useEffect } from 'react';
function PricingPage() {
useEffect(() => {
new InteractivePricingTable();
}, []);
return (
<div dangerouslySetInnerHTML={{ __html: pricingHTML }} />
);
}Vue Integration
<template>
<div v-html="pricingHTML"></div>
</template>
<script>
export default {
mounted() {
new InteractivePricingTable();
}
}
</script>This interactive pricing table provides a complete solution for showcasing subscription plans with smooth animations, comparison tools, and excellent user experience across all devices.
HTML
4
lines
CSS
6
lines
<div class="pricing-container">
<h2>Interactive Pricing Table</h2>
<p>Choose the perfect plan for your needs</p>
</div>