Skip to content
All Taste components

Pricing

Plan comparison table

Every plan's features in one table, grouped by topic, for people who want the detail.

3 plans · grouped rows · ticks, dashes and values · highlighted column

Compare plans

Free$0Pro$12/moStudio$29/mo
Invoicing
Invoices a month5UnlimitedUnlimited
Recurring invoicesNot includedIncludedIncluded
24 currenciesIncludedIncludedIncluded
Getting paid
Card and bank paymentsIncludedIncludedIncluded
Custom reminder scheduleNot includedIncludedIncluded
Automatic late feesNot includedIncludedIncluded
Team
Seats115
Approval before sendingNot includedNot includedIncluded
Client portalNot includedNot includedIncluded
import { Check, Minus } from "lucide-react";
import { cn } from "@/lib/utils";

const plans = [
  { name: "Free", price: "$0" },
  { name: "Pro", price: "$12/mo", highlight: true },
  { name: "Studio", price: "$29/mo" },
];

// true = included, false = not included, string = a value
type Cell = boolean | string;
const groups: { name: string; rows: { feature: string; values: [Cell, Cell, Cell] }[] }[] = [
  { name: "Invoicing", rows: [
    { feature: "Invoices a month", values: ["5", "Unlimited", "Unlimited"] },
    { feature: "Recurring invoices", values: [false, true, true] },
    { feature: "24 currencies", values: [true, true, true] },
  ] },
  { name: "Getting paid", rows: [
    { feature: "Card and bank payments", values: [true, true, true] },
    { feature: "Custom reminder schedule", values: [false, true, true] },
    { feature: "Automatic late fees", values: [false, true, true] },
  ] },
  { name: "Team", rows: [
    { feature: "Seats", values: ["1", "1", "5"] },
    { feature: "Approval before sending", values: [false, false, true] },
    { feature: "Client portal", values: [false, false, true] },
  ] },
];

function Value({ value }: { value: Cell }) {
  if (value === true) return <><Check className="mx-auto size-4 text-primary" aria-hidden /><span className="sr-only">Included</span></>;
  if (value === false) return <><Minus className="mx-auto size-4 text-fg-subtle" aria-hidden /><span className="sr-only">Not included</span></>;
  return <span className="text-fg">{value}</span>;
}

export function PlanComparison() {
  return (
    <section aria-labelledby="compare-title" className="bg-bg font-sans">
      <div className="mx-auto max-w-4xl px-4 py-20 sm:px-6">
        <h2 id="compare-title" className="text-center text-3xl font-semibold tracking-tight text-fg">Compare plans</h2>
        <div className="mt-10 overflow-x-auto">
          <table className="w-full min-w-[480px] table-fixed border-collapse text-sm">
            <thead>
              <tr>
                <td className="w-2/5" />
                {plans.map((p) => (
                  <th key={p.name} scope="col" className={cn("px-2 pb-4 pt-3 text-center align-bottom font-semibold text-fg", p.highlight && "rounded-t-lg bg-primary-soft text-primary-soft-fg")}>
                    {p.name}
                    <span className="block text-xs font-normal text-fg-subtle">{p.price}</span>
                  </th>
                ))}
              </tr>
            </thead>
            {groups.map((g) => (
              <tbody key={g.name}>
                <tr>
                  <th scope="colgroup" colSpan={4} className="border-b border-border-strong pb-2 pt-6 text-left text-xs font-medium text-fg">{g.name}</th>
                </tr>
                {g.rows.map((r) => (
                  <tr key={r.feature}>
                    <th scope="row" className="border-b border-border py-3 pr-2 text-left font-normal text-fg-muted">{r.feature}</th>
                    {r.values.map((v, i) => (
                      <td key={i} className={cn("border-b border-border px-2 py-3 text-center", plans[i].highlight && "bg-primary-soft/40")}>
                        <Value value={v} />
                      </td>
                    ))}
                  </tr>
                ))}
              </tbody>
            ))}
          </table>
        </div>
      </div>
    </section>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.