DEV Community

Cover image for How to create an interactive pricing table with Tailwind CSS and JavaScript
Michael Andreuzza
Michael Andreuzza

Posted on

How to create an interactive pricing table with Tailwind CSS and JavaScript

It's Monday! Let's get started with an interactive pricing table. Remember we did this with Tailwind CSS and Alpine.js? But first of all, an intro.

See it live and get the code

What is and pricing tabel toggle?

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 relveant to the tutorial.

The buttons

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>
Enter fullscreen mode Exit fullscreen mode

The array

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...
];
Enter fullscreen mode Exit fullscreen mode

The cards

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 button
  • href={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>
  ))
}
Enter fullscreen mode Exit fullscreen mode

The script

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);
});
Enter fullscreen mode Exit fullscreen mode

Conclusion

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.

Top comments (0)