It's Christmas, get a 30% OFF. Apply code XMAS at checkout.
It’s Monday! Let’s get started with an interactive pricing table. Remember we did this with Tailwind CSS and Alpine.js? If not you can see it here. So let’s do it again but with javaScript. But first of all, an intro.
A pricing table toggle is a way to show for example monthly or annual pricing plans. It’s a great way to make it easy for users to switch between plans.
This is the structure of the project: Understanding the code:
Classes are removed for brevity, but I’ll keep those classes relevant to the tutorial.
These buttons will be used to change the pricing of any card on the pricing table
id="monthlyBtn"
: This is the id of the button that will change the pricing of the card to monthly.id="annualBtn"
: This is the id of the button that will change the pricing of the card to annual.<div>
<button
id="monthlyBtn">
Monthly
</button>
<button
id="annualBtn">
Annual
</button>
</div>
To simplify the code, we’ll use an array that store the pricing plans data, you don’t really want to hardcode the data in the HTML. It would be a pain to maintain it. So let’s create an array to store the data. Let’s add it on the same page, so we can access it easily and avoid looking for it.
const pricingPlans = [...]
: This is the array that will store the pricing plans data.name: "Starter Pack",
: This is the name of the plan.link: "#_",
: This is the link of the plan.monthlyPrice: "15",
: This is the monthly price of the plan.annualPrice: "8",
: This is the annual price of the plan.description: "This plan is ideal for individual users...",
: This is the description of the plan.cardBgClass: "bg-black/20",
: This is the background color of the card.buttonClass: "text-white bg-black/50 hover:bg-black/20",
: This is the button color of the card.features: ["5 mb/PDF", "75 pages/PDF"],
: This is the features of the plan.unavailableFeatures: ["Gpt-3.5-turbo model"],
: This is the unavailable features of the plan.const pricingPlans = [
{
name: "Starter Pack",
link: "#_",
monthlyPrice: "15",
annualPrice: "8",
description: "This plan is ideal for individual users...",
cardBgClass: "bg-black/20",
buttonClass: "text-white bg-black/50 hover:bg-black/20",
features: ["5 mb/PDF", "75 pages/PDF"],
unavailableFeatures: ["Gpt-3.5-turbo model"],
},
// More plans...
];
This is the template literall that will be used to render the pricing plans according to the data in the array.
pricingPlans.map((plan) => (
: This is the array that will be used to iterate over the pricing plans.data-monthly-price={plan.monthlyPrice}
: This is the data attribute that will be used to store the monthly price of the plan.data-annual-price={plan.annualPrice}
: This is the data attribute that will be used to store the annual price of the plan.class={plan.cardBgClass}
: This is the class that will be used to style the card. Is a variable that will be used to store the background color of the card. We need one of the cards to be “popular” so we can style it differently.{plan.name}
: This is the name of the plan.<span>${plan.monthlyPrice}</span>
: This is the span that will be used to display the monthly price of the plan.<span>${plan.annualPrice}</span>
: This is the span that will be used to display the annual price of the plan.{plan.description}
: This is the description of the plan.{plan.features.map((feature) => (
: This is the array that will be used to iterate over the available features of the plan.{plan.unavailableFeatures.map((feature) => (
: This is the array that will be used to iterate over the unavailable features of the plan.class={
${plan.buttonClass}}>
: This is the class that will be used to style the buttonhref={plan.link}
: This is the href that will be used to link to the plan.{
pricingPlans.map((plan) => (
<div
data-monthly-price={plan.monthlyPrice}
data-annual-price={plan.annualPrice}
class={`${plan.cardBgClass}`}>
<div>
<div >
<p>
{plan.name}
</p>
<p>
<span>
<span >${plan.monthlyPrice}</span>
<span >${plan.annualPrice}</span>
</span>
<span>
/m
<span
style="display: none;">
(billed annually)
</span>
</span>
</p>
</div>
<p>{plan.description}</p>
<ul>
{plan.features.map((feature) => (
<li>
<svg>
<!-- Icons for available features goes here -->
</svg>
{feature}
</li>
))}
{plan.unavailableFeatures.map((feature) => (
<li>
<svg>
<!-- Icons for NON available features goes here -->
</svg>
{feature}
</li>
))}
</ul>
</div>
<div>
<a
href={plan.link}
class={`${plan.buttonClass}`}>
Get started
</a>
</div>
</div>
))
}
This is the script that will be used to update the pricing plans according to the user’s choice.
document.addEventListener("DOMContentLoaded", function () {
: This is the event listener that will be used to run the code when the DOM is loaded.const monthlyBtn = document.getElementById("monthlyBtn");
: This is the code that will be used to get the monthly button element.const annualBtn = document.getElementById("annualBtn");
: This is the code that will be used to get the annual button element.monthlyBtn.addEventListener("click", toggleBillingCycle);
: This is the code that will be used to add an event listener to the monthly button.annualBtn.addEventListener("click", toggleBillingCycle);
: This is the code that will be used to add an event listener to the annual button.function toggleBillingCycle() {
: This is the code that will be used to define the toggleBillingCycle function.const isAnnual = this.id === "annualBtn";
: This is the code that will be used to check if the button that was clicked is the annual button.const activeBtn = isAnnual ? annualBtn : monthlyBtn;
: This is the code that will be used to get the active button.const inactiveBtn = isAnnual ? monthlyBtn : annualBtn;
: This is the code that will be used to get the inactive button.activeBtn.classList.add("bg-black/50", "text-white");
: This is the code that will be used to add the active button class.inactiveBtn.classList.remove("bg-black/50", "text-black");
: This is the code that will be used to remove the inactive button class.updatePricingDisplay(isAnnual);
: This is the code that will be used to update the pricing display. document.addEventListener("DOMContentLoaded", function () {
const monthlyBtn = document.getElementById("monthlyBtn");
const annualBtn = document.getElementById("annualBtn");
monthlyBtn.addEventListener("click", toggleBillingCycle);
annualBtn.addEventListener("click", toggleBillingCycle);
function toggleBillingCycle() {
const isAnnual = this.id === "annualBtn";
const activeBtn = isAnnual ? annualBtn : monthlyBtn;
const inactiveBtn = isAnnual ? monthlyBtn : annualBtn;
activeBtn.classList.add("bg-black/50", "text-white");
inactiveBtn.classList.remove("bg-black/50", "text-black");
updatePricingDisplay(isAnnual);
}
function updatePricingDisplay(isAnnual) {
const plans = document.querySelectorAll(".pricing-card");
plans.forEach((plan) => {
const priceElement = plan.querySelector(".actualPrice");
const billingCycleElement = plan.querySelector(".actualCycle");
const monthlyPrice = plan.dataset.monthlyPrice;
const annualPrice = plan.dataset.annualPrice;
priceElement.textContent = isAnnual ? annualPrice : monthlyPrice;
billingCycleElement.textContent = isAnnual ? "(monthly billed annually)" : "/m";
});
}
updatePricingDisplay(false);
});
In this tutorial, we learned how to create an interactive pricing table with Tailwind CSS and JavaScript. We created a pricing table that allows users to switch between monthly and annual pricing plans. We also added a link to each plan and used JavaScript to update the pricing display when the user clicks on the monthly or annual button. This tutorial is a great starting point for anyone looking to create an interactive pricing table with Tailwind CSS and JavaScript. Do not forget to make it responsive and fully accessible.
Hope you enjoyed this tutorial and learned something new.
/Michael Andreuzza
Unlock all themes for $199 for forever! Includes lifetime updates, new
themes, unlimited projects, and support. No subscription needed.
— No subscription required!