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.
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>
)
}
pnpm dlx shadcn add @01orbital/two-plan-pricing-02npx shadcn add @01orbital/two-plan-pricing-02yarn shadcn add @01orbital/two-plan-pricing-02bunx --bun shadcn add @01orbital/two-plan-pricing-02Free 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.
import TwoPlanPricing02 from "@/components/blocks/pricing/two-plan-pricing-02"
export default function Example() {
return <TwoPlanPricing02 />
}npm: @phosphor-icons/react, cn. The CLI installs them for you.
Registry pieces it installs with it:
Two-Plan Pricing with Banners
Two plans in joined pricing cells, each topped by a CelestographPlaceholder banner seeded from the plan name, with a Most teams badge and a solid button on the featured plan.
Compare
Every About block side by side: whether it follows the theme or stays dark, the stock parts it is built on, and whether it is free. Open one for its preview, props and install.