PricingPlan
A single plan on a pricing page — name, price, a `CheckList` of what it includes, and a call to action. `highlight` marks the recommended one, which colors the card and turns its button solid.
<UiPricingPlan />Options
One block per prop — what it does, and what it looks like set.
Title
title is the plan's name, and the first thing read on the card. Keep it to the word a customer would use in a sentence — 'I'm on Pro' — not a marketing phrase.
Pro
Description
description is the one line under the name saying who the plan is for. It's what saves a reader from comparing four feature lists to work out which column is theirs.
Pro
For small teams shipping together.
Badge
badge is the pill beside the name — 'Most popular', 'Save 20%'. A bare string takes the plan's own color; pass an object to color it yourself. It's a claim about the plan, so use it on exactly one plan in a row, and pair it with highlight.
Pro
Most popularA bare string.
Team
Save 20%An object, colored.
Price
price is a string, never a number: currency symbol, separators and locale are the app's to decide, and a plan whose price is 'Free' or 'Custom' isn't a number at all. Format it however your pricing page already does.
Free
Pro
Enterprise
Discount
discount is what the plan costs right now, when that's less than price. Setting it strikes price out and promotes this to the headline figure — so a plan on offer sets both, and price on its own is the ordinary case. It's named after the offer rather than after the number, matching Nuxt UI.
Pro
Pro
price is the regular figure and discount is what it drops to, so the *smaller* number goes in discount and a plan on offer sets both. Setting discount on its own renders it as the only price, with nothing struck out.
Billing cycle
billingCycle is what the price buys, printed right after it — '/month', '/seat', '/1,000 credits'. Without it a bare figure means nothing; with it the price row reads as one sentence.
Pro
Team
Billing period
billingPeriod is when the money actually moves, in small print under the price. It's the line that keeps a monthly figure honest when the plan is billed a year at a time — the single most common complaint about a pricing page. A compact plan has no room for a second line, so it hangs the same text off an Info beside the billing cycle instead.
Pro
billed annually
Pro
For growing teams
Features
features renders as a CheckList. A bare string is an included feature; an object is a full CheckListItem, so checked: false tones a feature down as something this plan leaves out, and description adds a second line under it.
Free
- 1 project
- Community support
- Custom domains
- SSO and audit logs
Pro
- Unlimited projects
- Custom domainsUp to 10, with automatic certificates
- Priority support
- SSO and audit logs
Feature strings are turned into CheckListItems, so everything CheckList accepts works here — { label, description, checked }. A checked: false feature stays in the list rather than disappearing from it, which is what keeps two plans lining up row for row.
Terms
terms is the small print under the button — 'No credit card required', 'Prices exclude VAT', 'Cancel any time'. It belongs under the button because that's where the hesitation is.
Pro
14 days free. No credit card required.
Highlight
highlight marks the plan you're recommending: the same card variant in the plan's color, and a button that goes solid unless it sets its own variant. Exactly one plan in a row should have it — two recommendations are none.
Free
- 1 project
Pro
Most popular- Unlimited projects
Scale
scale grows the card slightly above its neighbours from md up. It only means anything beside other plans, so PricingPlans applies it to the highlighted plan for you rather than making you set it per card.
Free
- 1 project
Pro
Most popular- Unlimited projects
Team
- Everything in Pro
scale is a transform, so the card grows out of its grid cell instead of pushing its neighbours. Give the row a little vertical padding (class="py-sm") or the top of the grown card gets clipped by whatever sits above it.
Orientation
horizontal moves the price and button beside the features instead of under them — for a plan that stands on its own, like a lifetime deal or an add-on above a comparison table. It stacks back to vertical below md, so it's safe on a phone. Both densities have both directions, so it combines with layout rather than excluding it.
Lifetime
LimitedPay once, use it forever.
one-time payment
- Every feature in Pro
- All future updates
- Priority support
Color
color is the accent, not the card: the highlighted card, the feature checkmarks, the button, and an uncolored badge. The card itself only takes the color when the plan is highlighted.
neutral
- Included
- Not included
primary (default)
- Included
- Not included
secondary
- Included
- Not included
success
- Included
- Not included
error
- Included
- Not included
warning
- Included
- Not included
info
- Included
- Not included
pending
- Included
- Not included
color tints the card itself only when the plan is also highlighted. On the rest it stays an accent — checkmarks, button, badge — because a row of plans each tinted a different color reads as decoration rather than as a recommendation.
Layout
layout sets the density. compact tightens the padding, drops the type a size and collapses the features to a dot-separated summary instead of a CheckList — for wherever the plans are a control rather than a pitch. It combines with orientation: horizontal gives the one-line switcher row, vertical a small card that still fits a lineup.
Free
For trying things out.
Pro
For small teams shipping together.
Team
For a company with a finance department.
Free
For trying things out.
Pro
For small teams shipping together.
Team
For a company with a finance department.
Variant
variant is the card itself, named after Card's variants. subtle is a raised panel with a faint ring; soft a flat tint with no ring, for plans on a page that's already busy; outline just the ring on the page background, the quietest of the three. A highlighted plan keeps its variant and only changes colour.
Free
For trying things out.
- 1 project
- Community support
Pro
For small teams shipping together.
- Unlimited projects
- Priority support
Team
For a company with a finance department.
- Everything in Pro
- SSO & audit logs
Free
For trying things out.
- 1 project
- Community support
Pro
For small teams shipping together.
- Unlimited projects
- Priority support
Team
For a company with a finance department.
- Everything in Pro
- SSO & audit logs
Free
For trying things out.
- 1 project
- Community support
Pro
For small teams shipping together.
- Unlimited projects
- Priority support
Team
For a company with a finance department.
- Everything in Pro
- SSO & audit logs
Examples
The component in real use: compositions that answer "how do I build X with this", rather than one prop at a time.
A monthly / annual toggle
The component never derives one price from another — it renders the strings it's given. Keep the billing period in your own state and compute the price props from it, which is also what lets the annual figure carry its own discount and billingPeriod.
Free
For trying things out.
- 1 project
- Community support
Pro
Save 17%For small teams shipping together.
billed annually
- Unlimited projects
- Custom domains
- Priority support
14 days free. No credit card required.
Enterprise
For organisations with a procurement team.
- Everything in Pro
- SSO and audit logs
- 99.9% uptime SLA
Prices are strings, and nothing here charges anyone
PricingPlan formats no numbers and calls no API. It renders the price strings you hand it and emits select when its button is clicked — the checkout, the subscription, the currency and the locale are all yours.
API Reference
Generated from the component's source — props, slots and emits as the component actually declares them.
Props
stringstring | PricingPlanBadgestringstringstringstring(string | CheckListItem)[]PricingPlanButtonbooleanfalsebooleanfalse"vertical" | "horizontal"'vertical'"neutral" | "primary" | "secondary" | "success" | "error" | "warning" | "info" | "pending"'primary'"default" | "compact"'default'"subtle" | "soft" | "outline"'subtle'Slots
headerpricedefaultfeaturesfooterEmits
select[]Types
type Color = "neutral" | "primary" | "secondary" | "success" | "error" | "warning" | "info" | "pending";interface PricingPlanBadge {
/**
* The pill's text — 'Most popular', 'Save 20%'.
*/
label: string;
/**
* Defaults to the plan's own `color`.
*/
color?: Color;
/**
* @defaultValue 'soft'
*/
variant?: "solid" | "soft";
}interface PricingPlanButton {
/**
* The button's text — 'Get started', 'Contact sales'.
*/
label: string;
/**
* Route or URL to navigate to. Leave it off and handle `select` instead when signing up needs
* to run something first (open a checkout, create a subscription).
*/
to?: string;
/**
* The target attribute for the link (e.g. '_blank').
*/
target?: string;
/**
* Name of the icon displayed inside the button.
*/
icon?: string;
/**
* Defaults to the plan's own `color` on a highlighted plan and `neutral` on the rest — so the
* recommended plan owns the only coloured call to action in the row.
*/
color?: Color;
/**
* Defaults to `solid` on a highlighted plan and `subtle` on the rest — which is what makes the
* recommended plan's call to action the loudest one in a row. A `disabled` button stays
* `subtle` either way: `Button` dims a disabled control to 50%, and half a solid fill reads as
* broken rather than as "you are already on this plan".
*/
variant?: "solid" | "subtle" | "soft" | "ghost";
/**
* @defaultValue 'md'
*/
size?: "sm" | "md" | "lg";
/**
* Disables the button — for the plan the viewer is already on.
* @defaultValue false
*/
disabled?: boolean;
}interface CheckListItem {
/**
* Text label for this item.
*/
label: string;
/**
* Secondary text shown below the label.
*/
description?: string;
/**
* Identity used for `v-model` when the list is interactive. Falls back to the item's index.
*/
value?: string | number;
/**
* Whether this item is checked. Used directly when the list isn't interactive; only used as the
* initial state when interactive and uncontrolled.
* @defaultValue true
*/
checked?: boolean;
/**
* Disables interaction with this item. Has no effect on a non-interactive list.
* @defaultValue false
*/
disabled?: boolean;
}