Pricing

Usage-Based Two-Plan Pricing

Two-plan pricing that sets a free tier with per-item usage fees against a featured paid tier that bundles them, with the fee or included amount in muted text after each metered feature.

Free, MIT licenseOpen in Browse
import { CheckIcon } from "@phosphor-icons/react/dist/ssr"
import { cn } from "cn"

import { Heading } from "@/components/editorial/heading"
import {
  Pricing,
  PricingCard,
  PricingCardAmount,
  PricingCardContent,
  PricingCardDescription,
  PricingCardFeature,
  PricingCardFeatures,
  PricingCardFooter,
  PricingCardHeader,
  PricingCardPeriod,
  PricingCardPrice,
  PricingCardTitle,
} from "@/components/editorial/pricing"
import {
  Section,
  SectionContent,
  SectionHeader,
  SectionTitleGroup,
} from "@/components/editorial/section"
import { buttonVariants } from "@/components/ui/button"

// The copy: change text here, not in the markup.
const COPY = {
  title: "Start free, upgrade when the project asks for it.",
  period: "/ month",
} as const

type Plan = {
  name: string
  price: string
  cta: string
  description: string
  features: { label: string; fee?: string }[]
  featured?: boolean
}

const PLANS: Plan[] = [
  {
    name: "Free",
    price: "$0",
    cta: "Begin on Free",
    description:
      "All features included, with no trial clock and no card required.",
    features: [
      { label: "Unlimited projects" },
      { label: "Preview deploys" },
      { label: "Custom domains", fee: "$2 each" },
      { label: "Team seats", fee: "$8 each" },
      { label: "Build minutes", fee: "$0.01 each" },
      { label: "Email support" },
    ],
  },
  {
    name: "Pro",
    price: "$25",
    cta: "Move to Pro",
    description: "Usage fees are bundled into one predictable price.",
    features: [
      { label: "Unlimited projects" },
      { label: "Preview deploys" },
      { label: "Custom domains", fee: "included" },
      { label: "Team seats", fee: "included" },
      { label: "Build minutes", fee: "10,000 included" },
      { label: "Priority support" },
    ],
    featured: true,
  },
]

export default function TwoPlanPricing02() {
  return (
    <Section>
      <SectionHeader align="center">
        <SectionTitleGroup>
          <Heading>{COPY.title}</Heading>
        </SectionTitleGroup>
      </SectionHeader>
      <SectionContent width="lg">
        <Pricing cols={2}>
          {PLANS.map((plan) => (
            <PricingCard key={plan.name} featured={plan.featured}>
              <PricingCardHeader>
                <PricingCardTitle>{plan.name}</PricingCardTitle>
                <PricingCardPrice>
                  <PricingCardAmount>{plan.price}</PricingCardAmount>
                  <PricingCardPeriod>{COPY.period}</PricingCardPeriod>
                </PricingCardPrice>
                <PricingCardDescription>
                  {plan.description}
                </PricingCardDescription>
              </PricingCardHeader>
              <PricingCardContent>
                <PricingCardFeatures>
                  {plan.features.map((f) => (
                    <PricingCardFeature key={f.label}>
                      <CheckIcon weight="bold" aria-hidden="true" />
                      <span>
                        {f.label}
                        {f.fee && (
                          <span className="text-muted-foreground">
                            {" "}
                            — {f.fee}
                          </span>
                        )}
                      </span>
                    </PricingCardFeature>
                  ))}
                </PricingCardFeatures>
              </PricingCardContent>
              <PricingCardFooter>
                <a
                  href="#"
                  data-slot="button"
                  className={cn(
                    buttonVariants({
                      variant: plan.featured ? "default" : "outline",
                    })
                  )}
                >
                  {plan.cta}
                </a>
              </PricingCardFooter>
            </PricingCard>
          ))}
        </Pricing>
      </SectionContent>
    </Section>
  )
}

Installation

pnpm dlx shadcn add @01orbital/two-plan-pricing-02
npx shadcn add @01orbital/two-plan-pricing-02
yarn shadcn add @01orbital/two-plan-pricing-02
bunx --bun shadcn add @01orbital/two-plan-pricing-02

Free under the MIT license. Add the @01orbital registry to components.json once (install guide), then run the command.

It lands at components/blocks/pricing/two-plan-pricing-02/index.tsx, as source you own and edit.

Usage

import TwoPlanPricing02 from "@/components/blocks/pricing/two-plan-pricing-02"

export default function Example() {
  return <TwoPlanPricing02 />
}

Dependencies

npm: @phosphor-icons/react, cn. The CLI installs them for you.

Registry pieces it installs with it: