Billing SDK/Billing SDK
Billing & Usage AnalyticsBilling Settings 2

Billing Settings 2

A comprehensive billing settings component with customizable input fields, feature toggles, currency selection, and built-in validation. Supports 180+ currencies and custom validation rules.

Playground
Custom Billing Settings

Manage your billing preferences and settings

Invoices will be sent to this email address

For VAT or other tax purposes

Auto-Renewal
Automatically renew your subscription
Invoice Emails
Receive emails when invoices are generated
Promotional Emails
Receive occasional updates about new features and offers
src/components/billing-settings-2-demo.tsx
'use client';

import { BillingSettings2 } from '@/components/billingsdk/billing-settings-2';
import { useState } from 'react';

export function BillingSettings2Demo() {
	const [inputValues, setInputValues] = useState({
		fullName: '',
		billingEmail: '',
		taxId: '',
	});

	const [featureToggles, setFeatureToggles] = useState({
		autoRenewal: true,
		invoiceEmails: true,
		promotionalEmails: false,
	});

	const [selectedCurrency, setSelectedCurrency] = useState('usd');

	const handleInputChange = (field: string, value: string) => {
		setInputValues(prev => ({
			...prev,
			[field]: value
		}));
	};

	// Handler wrappers
	const createInputChangeHandler = (field: string) => (value: string) => {
		handleInputChange(field, value);
	};

	const createCurrencyChangeHandler = (setCurrency: (value: string) => void) => (value: string) => {
		console.log('Currency changed to:', value);
		setCurrency(value);
		// Add: updatePricing(value), savePreference(value), etc.
	};

	const handleFeatureToggle = (feature: string, enabled: boolean) => {
		setFeatureToggles(prev => ({
			...prev,
			[feature]: enabled
		}));
	};

	const handleSave = () => {
		// Validation passed if we reach here
		alert('Settings saved successfully!');
		console.log('Input values:', inputValues);
		console.log('Feature toggles:', featureToggles);
		console.log('Selected currency:', selectedCurrency);
	};

	const handleCancel = () => {
		alert('Changes cancelled!');
	};

	return (
		<div className="p-6">
			<BillingSettings2
				title="Custom Billing Settings"
				inputFields={[
					{
						id: "fullName",
						name: "fullName",
						value: inputValues.fullName,
						placeholder: "Enter your full name",
						onChange: createInputChangeHandler('fullName'),
						label: "Full Name",
						type: "text",
						required: true,
						validation: {
							minLength: 2,
							maxLength: 50,
						},
					},
					{
						id: "billingEmail",
						name: "billingEmail",
						value: inputValues.billingEmail,
						placeholder: "user@example.com",
						onChange: createInputChangeHandler('billingEmail'),
						label: "Billing Email",
						helperText: "Invoices will be sent to this email address",
						type: "email",
						required: true,
					},
					{
						id: "taxId",
						name: "taxId",
						value: inputValues.taxId,
						placeholder: "EU123456789",
						onChange: createInputChangeHandler('taxId'),
						label: "Tax ID (Optional)",
						helperText: "For VAT or other tax purposes",
						type: "text",
						validation: {
							pattern: /^[A-Z]{2}\d{8,12}$/,
							customValidator: (value: string) => {
								if (value && !/^[A-Z]{2}\d{8,12}$/.test(value)) {
									return "Tax ID should be in format: XX followed by 8-12 digits (e.g., EU123456789)";
								}
								return null;
							},
						},
					},
				]}
				features={[
					{
						id: "auto-renewal",
						label: "Auto-Renewal",
						description: "Automatically renew your subscription",
						enabled: featureToggles.autoRenewal,
						onToggle: (enabled) => handleFeatureToggle('autoRenewal', enabled),
					},
					{
						id: "invoice-emails",
						label: "Invoice Emails",
						description: "Receive emails when invoices are generated",
						enabled: featureToggles.invoiceEmails,
						onToggle: (enabled) => handleFeatureToggle('invoiceEmails', enabled),
					},
					{
						id: "promotional-emails",
						label: "Promotional Emails",
						description: "Receive occasional updates about new features and offers",
						enabled: featureToggles.promotionalEmails,
						onToggle: (enabled) => handleFeatureToggle('promotionalEmails', enabled),
					},
				]}
				// CURRENCY: Shows all 180+ currencies by default
				// currencies={['USD', 'EUR', 'GBP']} // Specific currencies
				// currencyOptions={[{value: 'btc', label: 'Bitcoin'}]} // Custom
				
				defaultCurrency={selectedCurrency}
				onCurrencyChange={createCurrencyChangeHandler(setSelectedCurrency)}
				onSave={handleSave}
				onCancel={handleCancel}
				saveButtonText="Save Preferences"
				cancelButtonText="Discard Changes"
			/>
			
			{/* 
			USAGE EXAMPLES:
			- Specific: currencies={['USD', 'EUR']}
			- Custom: currencyOptions={[{value: 'btc', label: 'Bitcoin'}]}
			- All: (no currency props) = 180+ currencies
			- Handler: onCurrencyChange={(c) => updatePricing(c)}
			*/}
		</div>
	);
}

Installation

npx shadcn@latest add @billingsdk/billing-settings-2 
pnpm dlx shadcn@latest add @billingsdk/billing-settings-2 
yarn dlx shadcn@latest add @billingsdk/billing-settings-2 
bunx shadcn@latest add @billingsdk/billing-settings-2 
npx @billingsdk/cli add billing-settings-2 
pnpm dlx @billingsdk/cli add billing-settings-2 
yarn dlx @billingsdk/cli add billing-settings-2 
bunx @billingsdk/cli add billing-settings-2 

Usage

import { BillingSettings2 } from '@/components/billingsdk/billing-settings-2';
<BillingSettings2
	title="Custom Billing Settings"
	enableValidation
	currencyRequired
	inputFields={[
		{
			id: "fullName",
			name: "fullName",
			value: inputValues.fullName,
			placeholder: "Enter your full name",
			onChange: (value) => handleInputChange('fullName', value),
			label: "Full Name",
			type: "text",
			required: true,
			validation: { 
				minLength: 2, 
				maxLength: 50,
				customValidator: (value) => {
					if (value && value.trim().length < 2) {
						return "Name must be at least 2 characters";
					}
					return null;
				}
			},
		},
		{
			id: "billingEmail",
			name: "billingEmail",
			value: inputValues.billingEmail,
			placeholder: "user@example.com",
			onChange: (value) => handleInputChange('billingEmail', value),
			label: "Billing Email",
			helperText: "Invoices will be sent to this email address",
			type: "email",
			required: true,
		},
		{
			id: "taxId",
			name: "taxId",
			value: inputValues.taxId,
			placeholder: "EU123456789",
			onChange: (value) => handleInputChange('taxId', value),
			label: "Tax ID (Optional)",
			helperText: "For VAT or other tax purposes",
			type: "text",
			validation: { 
				pattern: /^[A-Z]{2}\d{8,12}$/,
				customValidator: (value) => {
					if (value && !/^[A-Z]{2}\d{8,12}$/.test(value)) {
						return "Tax ID format: XX followed by 8-12 digits";
					}
					return null;
				}
			},
		},
	]}
	features={[
		{
			id: "auto-renewal",
			label: "Auto-Renewal",
			description: "Automatically renew your subscription",
			enabled: featureToggles.autoRenewal,
			onToggle: (enabled) => handleFeatureToggle('autoRenewal', enabled),
		},
		{
			id: "invoice-emails",
			label: "Invoice Emails",
			description: "Receive emails when invoices are generated",
			enabled: featureToggles.invoiceEmails,
			onToggle: (enabled) => handleFeatureToggle('invoiceEmails', enabled),
		},
		{
			id: "promotional-emails",
			label: "Promotional Emails",
			description: "Receive occasional updates about new features and offers",
			enabled: featureToggles.promotionalEmails,
			onToggle: (enabled) => handleFeatureToggle('promotionalEmails', enabled),
		},
	]}
	// Option 1: Use specific currencies (string array)
	currencies={['USD', 'EUR', 'GBP', 'CAD', 'AUD']}
	// Option 2: Use custom currency options (overrides currencies prop)
	// currencyOptions={[
	// 	{ value: "usd", label: "USD - US Dollar" },
	// 	{ value: "eur", label: "EUR - Euro" },
	// 	{ value: "btc", label: "BTC - Bitcoin" },
	// ]}
	// Option 3: Leave both undefined for all 180+ currencies
	defaultCurrency="usd"
	onCurrencyChange={(value) => {
		setSelectedCurrency(value);
		// Additional logic: updatePricing(value), savePreference(value), etc.
	}}
	onSave={handleSave}
	onCancel={handleCancel}
	saveButtonText="Save Preferences"
	cancelButtonText="Discard Changes"
/>

Props

PropTypeDefaultDescription
titlestring"Billing Settings"The title displayed at the top of the component
featuresFeatureToggle[]See belowArray of feature toggle configurations
inputFieldsInputField[]See belowArray of input field configurations
onSave() => void() => {}Function called when save button is clicked
onCancel() => void() => {}Function called when cancel button is clicked
saveButtonTextstring"Save Changes"Text for the save button
cancelButtonTextstring"Cancel"Text for the cancel button
currenciesstring[] (optional)undefinedArray of currency codes to show (e.g., ['USD', 'EUR', 'GBP']). Shows all 180+ currencies if undefined
currencyOptions{value: string, label: string}[] (optional)undefinedCustom currency options. Overrides currencies prop when provided
defaultCurrencystring (optional)"USD"Default selected currency (case-insensitive)
onCurrencyChange(value: string) => void (optional)() => {}Function called when currency is changed
enableValidationboolean (optional)trueEnables built-in validation and error display
currencyRequiredboolean (optional)trueRequires a currency selection when saving
classNamestringundefinedAdditional CSS classes to apply

FeatureToggle Object

PropertyTypeDescription
idstringUnique identifier for the feature
labelstringDisplay label for the feature
descriptionstringDescription of what the feature does
enabledbooleanCurrent state of the feature toggle
onToggle(enabled: boolean) => voidFunction called when toggle is switched

InputField Object

PropertyTypeDescription
idstringUnique identifier for the input field
namestringName attribute for the input field
valuestring (optional)Current value of the input field (controlled)
defaultValuestring (optional)Default value for uncontrolled input
placeholderstringPlaceholder text for the input field
onChange(value: string) => voidFunction called when input value changes
labelstringLabel displayed above the input field
helperTextstring (optional)Helper text displayed below the input field
type'text' | 'email' | 'tel' | 'url' | 'number'Type of input field
requiredboolean (optional)Whether the field is required
validationValidationRules (optional)Optional validation rules object

ValidationRules Object

PropertyTypeDescription
minLengthnumber (optional)Minimum character length
maxLengthnumber (optional)Maximum character length
patternRegExp (optional)Regular expression pattern to match
customValidator(value: string) => string | null (optional)Custom validation function that returns error message or null

Currency Configuration

All currency props are optional! The component supports three different currency configuration modes:

1. All Currencies (Default)

// Shows all 180+ currencies from currency-codes package
<BillingSettings2 />

2. Specific Currencies

// Shows only specified currency codes
<BillingSettings2 
	currencies={['USD', 'EUR', 'GBP', 'CAD', 'AUD']}
/>

3. Custom Currency Options

// Fully custom currency list (overrides currencies prop)
<BillingSettings2 
	currencyOptions={[
		{ value: "usd", label: "USD - US Dollar" },
		{ value: "eur", label: "EUR - Euro" },
		{ value: "btc", label: "BTC - Bitcoin" },
		{ value: "custom", label: "Custom Token" },
	]}
/>

Note: When validation fails, the save button is disabled. It re-enables automatically as users correct invalid fields. Error messages are shown inline beneath each field.

Examples

Basic Setup

import { BillingSettings2 } from '@/components/billingsdk/billing-settings-2';

export function BasicBillingSettings() {
  return (
    <BillingSettings2
      title="Account Settings"
      onSave={() => console.log('Settings saved')}
      onCancel={() => console.log('Changes cancelled')}
    />
  );
}

With Custom Validation

const customValidator = (value: string) => {
  if (value.includes('test')) {
    return "Test values are not allowed";
  }
  return null;
};

<BillingSettings2
  inputFields={[
    {
      id: "companyName",
      name: "companyName", 
      value: companyName,
      onChange: setCompanyName,
      label: "Company Name",
      validation: {
        minLength: 3,
        customValidator
      }
    }
  ]}
/>

Specific Currencies Only

<BillingSettings2
  currencies={['USD', 'EUR', 'GBP', 'JPY']}
  defaultCurrency="usd"
  onCurrencyChange={(currency) => {
    // Update pricing, save preference, etc.
    updatePricing(currency);
  }}
/>

Disable Validation

<BillingSettings2
  enableValidation={false}
  currencyRequired={false}
  // Save button will always be enabled
/>

Features

  • Built-in Validation: Email validation, pattern matching, custom validators
  • Currency Support: 180+ currencies via currency-codes package
  • Flexible Configuration: Custom input fields and feature toggles
  • Accessibility: ARIA labels, keyboard navigation, screen reader support
  • TypeScript: Full type safety with TypeScript interfaces
  • Responsive Design: Works on mobile and desktop

Dependencies

This component depends on:

  • currency-codes: For comprehensive currency data
  • shadcn/ui: Button, Card, Input, Label, Select, Switch components

Credits