Billing Plan Selector
hextaui/billing-plan-selectorFreeComponent
Select subscription plans with monthly/annual billing toggle.
Install it
npx shadcn@latest add https://hextaui.com/r/billing-plan-selector.jsonSource
1"use client";23import { Check, Loader2 } from "lucide-react";4import { useState } from "react";5import { cn } from "@/lib/utils";6import { Badge } from "@/registry/new-york/ui/badge";7import { Button } from "@/registry/new-york/ui/button";8import {9 Card,10 CardContent,11 CardDescription,12 CardHeader,13 CardTitle,14} from "@/registry/new-york/ui/card";15import { Switch } from "@/registry/new-york/ui/switch";1617export interface PlanFeature {18 name: string;19 included?: boolean;20 limit?: number | string;21 tooltip?: string;22}2324export interface SelectablePlan {25 id: string;26 name: string;27 description?: string;28 price: {29 monthly: number;30 annual: number;31 };32 currency?: string;33 features: PlanFeature[];34 isPopular?: boolean;35 isCurrent?: boolean;36 ctaLabel?: string;37 disabled?: boolean;38}3940export interface BillingPlanSelectorProps {41 plans: SelectablePlan[];42 selectedPlanId?: string;43 billingPeriod?: "monthly" | "annual";44 onBillingPeriodChange?: (period: "monthly" | "annual") => void;45 onPlanSelect?: (planId: string) => void;46 className?: string;47 showAnnualSavings?: boolean;48 currency?: string;49 layout?: "grid" | "list";50}5152function formatPrice(53 amount: number,54 currency = "USD",55 period: "monthly" | "annual" = "monthly"56): string {57 const formatter = new Intl.NumberFormat("en-US", {58 style: "currency",59 currency,60 minimumFractionDigits: 0,61 maximumFractionDigits: 0,62 });6364 const formatted = formatter.format(amount);65 return period === "monthly" ? `${formatted}/mo` : `${formatted}/yr`;66}6768export default function BillingPlanSelector({69 plans,70 selectedPlanId,71 billingPeriod = "monthly",72 onBillingPeriodChange,73 onPlanSelect,74 className,75 showAnnualSavings = true,76 currency = "USD",77 layout = "grid",78}: BillingPlanSelectorProps) {79 const [isLoading, setIsLoading] = useState<string | null>(null);8081 const handlePlanSelect = async (planId: string) => {82 setIsLoading(planId);83 try {84 await onPlanSelect?.(planId);85 } finally {86 setIsLoading(null);87 }88 };8990 const calculateSavings = (plan: SelectablePlan): number | null => {91 if (!showAnnualSavings || billingPeriod === "annual") return null;92 const monthlyTotal = plan.price.monthly * 12;93 const annualTotal = plan.price.annual;94 const savings = monthlyTotal - annualTotal;95 return savings > 0 ? savings : null;96 };9798 const defaultCurrency = currency || plans[0]?.currency || "USD";99100 return (101// … truncated
What it pulls in
Other registry items
Files it writes
More from HextaUI
All 139 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | HextaUI | Components | Free | 1 dep | |
| AI Chat Historyai-chat-history | HextaUI | Components | Free | no deps | |
| AI Citationsai-citations | HextaUI | Components | Free | no deps | |
| AI Conversationai-conversation | HextaUI | Components | Free | no deps | |
| AI Error Handlerai-error-handler | HextaUI | Components | Free | no deps | |
| AI File Uploadai-file-upload | HextaUI | Components | Free | no deps | |
| AI Messageai-message | HextaUI | Components | Free | 4 deps | |
| AI Model Selectorai-model-selector | HextaUI | Components | Free | no deps |
