It's Christmas, get a 30% OFF. Apply code XMAS at checkout.

← Back to all tutorials

How to create an interactive pricing table with Astro, Tailwind CSS, and Alpine.js

Pricing table with Alpine.js
Published and written on Feb 26 2024 by Michael Andreuzza

This tutorial delves into creating a responsive and interactive pricing table component, leveraging the powerful combination of Astro for static generation, Tailwind CSS for styling, and Alpine.js for interactivity. Our focus will be on the dynamic aspects of the component, particularly how Alpine.js works and how Astro passes data through an array to render our pricing plans.

Let’s populate the array for the pricing plans

Starting with the pricingPlans array, the backbone of our component. This array contains objects, each representing a different pricing plan and styles for our pricing cards, because of course, we need to think about UX.

const pricingPlans = [
  {
    name: "Starter Pack",
    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...
];

Each plan includes details such as pricing, descriptions, styling classes, and arrays of available and unavailable features.

Rendering the Component with Astro

Using Astro’s component model, we dynamically render each pricing plan. Astro’s template syntax allows us to iterate over the pricingPlans array, generating the markup for each plan:

---
// Import statements and the pricingPlans array defined here
---
 <BaseLayout>
    <div x-data="{ annual: false }">
      <!-- Pricing Plans Rendering -->
      {pricingPlans.map((plan) => (
        <div class={`rounded-xl overflow-hidden shadow-lg ${plan.cardBgClass}`}>
          <!-- Content goes here -->
        </div>
      ))}
    </div>
</BaseLayout>

Styling with Tailwind CSS

Within each plan’s markup, Tailwind CSS classes are applied for styling. This approach ensures our pricing table is not only functional but also visually appealing and responsive:

<div class="text-xl font-semibold text-neutral-800">{plan.name}</div>
<div class="mt-4">
  <span class="text-4xl font-bold">${plan.monthlyPrice}</span>
  <span class="text-base">/ month</span>
</div>
<!-- More styling with Tailwind CSS -->

For each pricing plan, we conditionally display the price based on this state:

<p>
  <span x-show="!annual">${plan.monthlyPrice}</span>
  <span x-show="annual">${plan.annualPrice}</span>
  /month
</p>

Dynamic Feature Listing

A key part of our pricing table is listing what’s included and what’s not. Using Alpine.js’s x-show, we dynamically render features based on their availability:

<ul>
  {plan.features.map((feature) => (
    <li x-show="available">
       <!-- Icons goes here -->
      {feature}</li>
  ))}
  {plan.unavailableFeatures.map((feature) => (
    <li x-show="!available" class="text-neutral-500">
    <!-- Icons goes here -->
    {feature}</li>
  ))}
</ul>

By combining Astro’s static generation with Tailwind CSS for styling and Alpine.js for interactivity, we’ve created a dynamic and responsive pricing table component. This tutorial showcases the power of integrating these modern web technologies to build interactive components efficiently.

Experiment with the code snippets provided, tweaking styles, and adding more features as you see fit. The flexibility of Astro, combined with the utility-first approach of Tailwind CSS and the reactivity of Alpine.js, offers a solid foundation for building sophisticated web interfaces.

/Michael Andreuzza

Did you like this tutorial? Please share it with your friends!

Unlock all themes for $199 for forever! Includes lifetime updates, new themes, unlimited projects, and support. No subscription needed.

— No subscription required!