Billing details
ProThe details printed on invoices, as a form: billing email, the name and tax ID on invoices, and the postal address. There is no card field: cards and payment methods belong at the billing provider's portal (Polar, Stripe), which invoice-history and subscription-status link to. Errors from your server show under the field they concern; Save stays locked, saying which field is missing, until the required ones are filled. "Saved" shows once a save resolves, until the next edit.
Version 5.2.0· other versions
This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).
Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1 and 2.6.2: the page came later, or had another name then.
Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.
Preview
Loading the preview
Install
First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/billing-details
Brings in: button, combobox, heading-level, heading-scope, input, locale, locked, tokens, utils · npm: lucide-react@^1.67.0
Usage
"use client"
import * as React from "react"
import { BillingDetails, type BillingField } from "@/components/candor/billing-details"
export default function Example() {
const [errors, setErrors] = React.useState<Partial<Record<BillingField, string>>>()
return (
<BillingDetails
className="max-w-lg"
taxIdLabel="VAT number"
countries={[
{ code: "GB", name: "United Kingdom" },
{ code: "IE", name: "Ireland" },
{ code: "US", name: "United States" },
]}
value={{ email: "accounts@keel.example", name: "Keel Ltd", line1: "1 Harbour Street", city: "Bristol", postalCode: "BS1 4AA", country: "GB" }}
errors={errors}
onSave={async (d) => {
await new Promise((r) => setTimeout(r, 400))
if (d.taxId && !/^GB\d{9}$/.test(d.taxId)) {
setErrors({ taxId: "That isn’t a UK VAT number: GB and nine digits." })
throw new Error("invalid")
}
setErrors(undefined)
}}
/>
)
}<BillingDetails>
| Prop | Type | Default | Description |
|---|---|---|---|
| value | Partial<BillingDetailsValue> | undefined | — | The details on file. Without it the form starts empty. |
| onSaverequired | (details: BillingDetailsValue) => void | Promise<void> | — | Called with the details; the button waits on a returned promise and shows Saved when it resolves. |
| countries | { code: string; name: string }[] | undefined | — | Countries to choose from, by ISO code and name. Without it, country is a text field. |
| taxIdLabel | string | undefined | — | What the tax ID is called where the account is, e.g. "VAT number" or "GSTIN". Defaults to "Tax ID". |
| errors | Partial<Record<BillingField, string>> | undefined | — | Your server's errors, by field, shown under each field. |
| error | string | undefined | — | An error that isn't about one field, in the app's words. |
| busy | boolean | undefined | false | The app is saving: the button says so. |
| className | string | undefined | — | Extra classes for the outer element. |
| headingLevel | HeadingLevel | undefined | — | The level of the form's heading, so it fits under the page's own headings. Default: one below the nearest `HeadingScope`, else 2 (`<h2>`). |
Strings
The fixed words, in English by default. Change any of them under billingDetails in <LocaleProvider strings={{ … }}>; the table is exported as billingDetailsStrings.
| Key | English |
|---|---|
| lockedSaving | Saving the details |
| heading | Billing details |
| intro | What appears on your invoices. Cards and payment methods are managed with the billing provider, not here. |
| Billing email | |
| emailHint | Invoices and payment receipts go here. |
| name | Name on invoices |
| namePlaceholder | Company or person |
| taxId | Tax ID |
| optional | {label} (optional) |
| address | Address |
| line1 | Address line 1 |
| line2 | Address line 2 |
| city | City |
| region | State, province or region |
| postalCode | Postal code |
| country | Country or region |
| countryPlaceholder | Choose a country or region |
| needs | Fill in {label}. |
| save | Save details |
| saving | Saving… |
| saved | Saved |
| saveFailed | Saving the details failed. |
Types
- BillingDetailsValue
- The details printed on invoices.
{ email: string; name: string; taxId?: string | undefined; line1: string; line2?: string | undefined; city: string; region?: string | undefined; postalCode?: string | undefined; /** An ISO 3166 code ("GB") when `countries` is given, else what the person typed. */ country: string; }- BillingField
keyof BillingDetailsValue
Types from other items
The props above take these. Each is defined by another item; import it from the path shown.
- HeadingLevel from @/lib/candor/heading-level
- A heading's level in the page's outline: `1` is `<h1>`, `6` is `<h6>`. Every Candor item that draws a heading takes its `headingLevel` as this type; the level is where the heading sits in the outline, never how large it looks.
1 | 2 | 3 | 4 | 5 | 6