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.
Manage your billing preferences and settings
Invoices will be sent to this email address
For VAT or other tax purposes
'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
Prop | Type | Default | Description |
---|---|---|---|
title | string | "Billing Settings" | The title displayed at the top of the component |
features | FeatureToggle[] | See below | Array of feature toggle configurations |
inputFields | InputField[] | See below | Array of input field configurations |
onSave | () => void | () => {} | Function called when save button is clicked |
onCancel | () => void | () => {} | Function called when cancel button is clicked |
saveButtonText | string | "Save Changes" | Text for the save button |
cancelButtonText | string | "Cancel" | Text for the cancel button |
currencies | string[] (optional) | undefined | Array of currency codes to show (e.g., ['USD', 'EUR', 'GBP'] ). Shows all 180+ currencies if undefined |
currencyOptions | {value: string, label: string}[] (optional) | undefined | Custom currency options. Overrides currencies prop when provided |
defaultCurrency | string (optional) | "USD" | Default selected currency (case-insensitive) |
onCurrencyChange | (value: string) => void (optional) | () => {} | Function called when currency is changed |
enableValidation | boolean (optional) | true | Enables built-in validation and error display |
currencyRequired | boolean (optional) | true | Requires a currency selection when saving |
className | string | undefined | Additional CSS classes to apply |
FeatureToggle Object
Property | Type | Description |
---|---|---|
id | string | Unique identifier for the feature |
label | string | Display label for the feature |
description | string | Description of what the feature does |
enabled | boolean | Current state of the feature toggle |
onToggle | (enabled: boolean) => void | Function called when toggle is switched |
InputField Object
Property | Type | Description |
---|---|---|
id | string | Unique identifier for the input field |
name | string | Name attribute for the input field |
value | string (optional) | Current value of the input field (controlled) |
defaultValue | string (optional) | Default value for uncontrolled input |
placeholder | string | Placeholder text for the input field |
onChange | (value: string) => void | Function called when input value changes |
label | string | Label displayed above the input field |
helperText | string (optional) | Helper text displayed below the input field |
type | 'text' | 'email' | 'tel' | 'url' | 'number' | Type of input field |
required | boolean (optional) | Whether the field is required |
validation | ValidationRules (optional) | Optional validation rules object |
ValidationRules Object
Property | Type | Description |
---|---|---|
minLength | number (optional) | Minimum character length |
maxLength | number (optional) | Maximum character length |
pattern | RegExp (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 datashadcn/ui
: Button, Card, Input, Label, Select, Switch components
Credits
- Created by @sapatmohit @tsahil01 @tejasnasre
Billing Settings
The Billing Settings component provides a user-friendly interface for managing billing preferences, payment methods, invoices, and usage limits. This component features a tabbed navigation system, form controls, and an interactive payment card management section.
Usage Meter Circle
Displays usage progress in a circular meter with an animated ring, status badges, and size variants.