Pricing cards
paddle/pricing-cardsFreeComponent
Responsive pricing tier cards with plan name, localized price, feature list, and per-card CTA. Supports current-plan highlighting and selection state for pricing pages and plan change flows.
Install it
npx shadcn@latest add https://developer.paddle.com/r/pricing-cards.jsonSource
1"use client"23import * as React from "react"4import { CheckIcon } from "lucide-react"5import {6 Card,7 CardContent,8 CardDescription,9 CardFooter,10 CardHeader,11 CardTitle,12} from "@/registry/new-york/ui/card"13import { Badge } from "@/registry/new-york/ui/badge"14import { Button } from "@/registry/new-york/ui/button"15import { Skeleton } from "@/registry/new-york/ui/skeleton"16import { cn } from "@/lib/utils"17import type { PriceData } from "@/registry/new-york/blocks/paddle-helpers/lib/paddle-types"1819/** Props for the `PricingTierCard` component. */20export type PricingTierCardProps = {21 name: string22 priceData?: PriceData23 description?: string24 features?: string[]25 badge?: string26 icon?: React.ReactNode27 onSelect?: () => void28 ctaLabel?: string29 isSelected?: boolean30 isCurrent?: boolean31 currentPlanLabel?: string32 badgePosition?: "left" | "center" | "right"33 loading?: boolean34 className?: string35}3637export function PricingTierCard({38 name,39 priceData,40 description,41 features,42 badge,43 icon,44 onSelect,45 ctaLabel,46 isSelected,47 isCurrent = false,48 currentPlanLabel = "Current plan",49 badgePosition = "center",50 loading = false,51 className,52}: PricingTierCardProps) {53 const { total, originalTotal, interval, trialPeriod } = priceData ?? {}5455 // undefined = checkout mode; defined (true/false) = selection mode56 const isSelectionVariant = isSelected !== undefined57 const resolvedCtaLabel =58 ctaLabel ??59 (isCurrent60 ? currentPlanLabel61 : isSelected62 ? "Selected"63 : isSelectionVariant64 ? "Select plan"65 : "Subscribe")6667 const showBadges = badge || isCurrent6869 // Custom onSelect (e.g. "Contact Sales") stays active on current plan70 const isDisabled = isCurrent && !onSelect7172 const ctaVariant = isCurrent ? "secondary" : isSelected ? "default" : "outline"7374 if (loading) {75 return (76 <Card className={cn("relative flex flex-col", className)}>77 <CardHeader className="pb-2">78 <div className="flex items-start gap-3">79 {icon && <Skeleton className="size-10 rounded-md shrink-0" />}80 <div className="flex-1 space-y-2">81 <Skeleton className="h-5 w-24" />82 <Skeleton className="h-4 w-full" />83 </div>84 </div>85 </CardHeader>86 <CardContent className="flex-1 space-y-3 pb-3">87 <div className="flex items-baseline gap-1">88 <Skeleton className="h-8 w-20" />89// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from paddle
All 14 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Billing interval togglebilling-interval-toggle | paddle | Components | Free | no deps | |
| Checkout summarycheckout-summary | paddle | Components | Free | no deps · 3 files | |
| Plan change breakdownplan-change-breakdown | paddle | Components | Free | 1 dep · 3 files | |
| Plan change previewplan-change-preview | paddle | Components | Free | 1 dep · 3 files | |
| Pricing select cardspricing-select-cards | paddle | Components | Free | 1 dep · 4 files | |
| Subscription alertsubscription-alert | paddle | Components | Free | 1 dep · 3 files | |
| Subscription payment cardsubscription-payment-card | paddle | Components | Free | 1 dep · 3 files | |
| Subscription status cardsubscription-status-card | paddle | Components | Free | 1 dep · 3 files |
