AIEO-ready websites that get cited by AITalk to us

Three Tier Pricing With Monthly Annual Toggle

A three-tier pricing grid with a pure-CSS monthly and annual billing toggle that swaps every price with no JavaScript, using a native checkbox and Tailwind group-has state.

React + TailwindNo dependenciespricingtierstoggleno-js
Original · free to use
npx shadcn@latest add https://webinnoventix.com/r/pricing-tier-toggle.json
pricing-tier-toggle.tsx
export default function PricingTierToggle() {
  const tiers = [
    {
      name: "Solo",
      blurb: "For individuals shipping their first ideas.",
      monthly: "£12",
      annual: "£9",
      featured: false,
      features: ["3 active projects", "5 GB storage", "Community support", "Basic analytics"],
    },
    {
      name: "Team",
      blurb: "For small teams that need to move quickly.",
      monthly: "£32",
      annual: "£26",
      featured: true,
      features: [
        "Unlimited projects",
        "100 GB storage",
        "Priority support",
        "Advanced analytics",
        "Team permissions",
      ],
    },
    {
      name: "Business",
      blurb: "For organisations with heavier demands.",
      monthly: "£64",
      annual: "£52",
      featured: false,
      features: [
        "Everything in Team",
        "1 TB storage",
        "Dedicated manager",
        "Audit logs",
        "Single sign-on",
      ],
    },
  ];

  return (
    <section className="bg-white px-6 py-16 dark:bg-zinc-950 md:py-24">
      <div className="group mx-auto max-w-6xl">
        <div className="text-center">
          <h2 className="text-3xl font-bold tracking-tight text-zinc-900 sm:text-4xl dark:text-white">
            Pricing that scales with you
          </h2>
          <p className="mx-auto mt-3 max-w-lg text-zinc-600 dark:text-zinc-400">
            Switch to annual billing and save around 20 per cent across every plan.
          </p>
        </div>

        <div className="mt-8 flex items-center justify-center gap-4">
          <span className="text-sm font-medium text-zinc-900 transition-colors group-has-[:checked]:text-zinc-400 dark:text-white dark:group-has-[:checked]:text-zinc-500">
            Monthly
          </span>
          <label className="relative inline-flex cursor-pointer items-center">
            <input type="checkbox" className="peer sr-only" aria-label="Switch to annual billing" />
            <span className="block h-7 w-12 rounded-full bg-zinc-300 transition-colors peer-checked:bg-indigo-600 peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-indigo-600 dark:bg-zinc-700" />
            <span className="pointer-events-none absolute left-1 top-1 h-5 w-5 rounded-full bg-white shadow transition-transform peer-checked:translate-x-5" />
          </label>
          <span className="flex items-center gap-1.5 text-sm font-medium text-zinc-400 transition-colors group-has-[:checked]:text-zinc-900 dark:text-zinc-500 dark:group-has-[:checked]:text-white">
            Annual
            <span className="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-400">
              Save 20%
            </span>
          </span>
        </div>

        <div className="mt-12 grid gap-6 lg:grid-cols-3">
          {tiers.map((tier) => (
            <div
              key={tier.name}
              className={
                "relative flex flex-col rounded-2xl border p-8 " +
                (tier.featured
                  ? "border-indigo-600 bg-white shadow-xl ring-1 ring-indigo-600 dark:border-indigo-500 dark:bg-zinc-900 dark:ring-indigo-500"
                  : "border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900/40")
              }
            >
              {tier.featured && (
                <span className="absolute -top-3 left-8 rounded-full bg-indigo-600 px-3 py-1 text-xs font-semibold text-white">
                  Most popular
                </span>
              )}

              <h3 className="text-lg font-semibold text-zinc-900 dark:text-white">{tier.name}</h3>
              <p className="mt-1 text-sm text-zinc-500 dark:text-zinc-400">{tier.blurb}</p>

              <div className="mt-6 flex items-baseline gap-1">
                <span className="text-4xl font-bold tracking-tight text-zinc-900 dark:text-white">
                  <span className="group-has-[:checked]:hidden">{tier.monthly}</span>
                  <span className="hidden group-has-[:checked]:inline">{tier.annual}</span>
                </span>
                <span className="text-sm text-zinc-500 dark:text-zinc-400">/mo</span>
              </div>
              <p className="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
                <span className="group-has-[:checked]:hidden">Billed monthly</span>
                <span className="hidden group-has-[:checked]:inline">Billed annually</span>
              </p>

              <a
                href="#"
                className={
                  "mt-6 rounded-lg px-4 py-2.5 text-center text-sm font-semibold transition focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 " +
                  (tier.featured
                    ? "bg-indigo-600 text-white hover:bg-indigo-500"
                    : "bg-zinc-900 text-white hover:bg-zinc-700 dark:bg-white dark:text-zinc-900 dark:hover:bg-zinc-200")
                }
              >
                Choose {tier.name}
              </a>

              <ul className="mt-8 space-y-3 border-t border-zinc-100 pt-6 text-sm dark:border-zinc-800">
                {tier.features.map((feature) => (
                  <li
                    key={feature}
                    className="flex items-start gap-3 text-zinc-700 dark:text-zinc-300"
                  >
                    <svg
                      className="mt-0.5 h-5 w-5 shrink-0 text-indigo-600 dark:text-indigo-400"
                      viewBox="0 0 20 20"
                      fill="currentColor"
                      aria-hidden="true"
                    >
                      <path
                        fillRule="evenodd"
                        d="M16.7 5.3a1 1 0 0 1 0 1.4l-7.5 7.5a1 1 0 0 1-1.4 0L3.3 10.7a1 1 0 1 1 1.4-1.4l3.8 3.8 6.8-6.8a1 1 0 0 1 1.4 0Z"
                        clipRule="evenodd"
                      />
                    </svg>
                    <span>{feature}</span>
                  </li>
                ))}
              </ul>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

Built by Web Innoventix. Free for personal and commercial use, no attribution required.

Built by Web Innoventix

Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.

Get a free quote

More blocks

All components
Chat with us