ComponentsForms & inputs

Billing details

The buyer's party for a Turkish e-Fatura / e-Arşiv invoice: an individual / company toggle, first and last name with a TCKN, or a company title with tax office and a VKN (or the owner's TCKN for a sole proprietorship), e-mail, phone and a structured address. Fields only — the same validateBillingDetails runs in the browser and on the server and returns a normalised party with its UBL-TR scheme (TCKN / VKN). No e-invoice integration.

Fieldset · Radio group (segmented) · ID input · Address field business/billing-details.tsx, business/billing-details-core.ts, locale-data/tr/id.tstheme · material · accent · density · font
Billing details

Try 10000000146 as a TCKN, or a VKN / TCKN for a company.

Foreign residents: the 99… number (YKN).

The invoice is sent here.

Billing address

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { BillingDetailsFields, billingDetailsFromFormData, billingErrorMessages, validateBillingDetails } from "@vamos-ui/react/business";

// page
<form action={saveBilling}>
  <BillingDetailsFields name="billing" defaultValue={{ type: "individual", address: { country: "TR" } }} />
</form>

// server action
async function saveBilling(data: FormData) {
  "use server";
  const v = validateBillingDetails(billingDetailsFromFormData(data, "billing"));
  if (!v.ok) return { errors: billingErrorMessages(v.errors) }; // pass back as errors={…}
  await customers.saveBillingParty(v.party!); // { type, name, taxId, taxScheme: "TCKN" | "VKN", taxOffice?, email, phone?, address }
}

A sole proprietorship (şahıs şirketi) invoices with the owner's TCKN, so the company tax number accepts 10-digit VKNs and 11-digit TCKNs; taxScheme tells which one it is.

The tax office is free text: there is no bundled list of tax offices.

Whether the buyer is registered for e-Fatura (and so gets an e-Fatura instead of an e-Arşiv invoice) is answered by your e-invoice provider, not by this form.

Examples

Turkish labels

The tr dictionary (@vamos-ui/react/locale/tr) gives Bireysel / Kurumsal, Unvan, Vergi dairesi, VKN and the Turkish error messages; billingErrorMessages(errors, tr.billingDetails) formats server errors the same way.

Fatura bilgileri

Şahıs şirketleri sahibinin TCKN'sini girer.

Fatura bu adrese gönderilir.

Fatura adresi

Companies only, with neighbourhoods

types={["company"]} hides the toggle (a hidden billing[type] is still posted); addressProps passes a neighbourhood source to the address fieldset; phone="required".

Invoice party

Sole proprietorships use the owner's TCKN.

The invoice is sent here.

Billing address

API

BillingDetailsFields

PropTypeDefault
value / defaultValue / onValueChange
{ type, firstName?, lastName?, nationalId?, companyName?, taxId?, taxOffice?, email?, phone?, address? }.
BillingDetails—
types
Offered party types; one type hides the toggle.
BillingPartyType[]["individual", "company"]
name
Form prefix: billing → billing[type], billing[taxId], billing[address][region1]… Read back with billingDetailsFromFormData(data, name).
string—
errors
Per-field messages (billingErrorMessages). The ID inputs also show their own checksum errors on blur.
Partial<Record<BillingField, ReactNode>>—
phone
The phone field.
"optional" | "required" | "hidden""optional"
addressProps
Passed to the address fieldset: sources (neighbourhoods), countries (default ["TR"]), fields, layout.
Partial<AddressFieldProps>—
legend / hint / size / disabled / labels
Fieldset legend (default "Billing details"), helper text, control size, built-in strings (billingDetails namespace).
…—

validateBillingDetails(details, opts)

PropTypeDefault
opts.allowUnknownTckn
Accept 11111111111, the placeholder TCKN e-Arşiv invoices use for a consumer who gives no ID number.
booleanfalse
opts.requirePhone
Phone becomes required.
booleanfalse
returns
errors: field → "required" | "invalid" | "tooLong" | "unknownTckn". party: name (full name or title), taxId digits, taxScheme, taxOffice, trimmed address.
{ ok, errors, party? }—

Helpers

PropTypeDefault
billingDetailsFromFormData(data, name = "billing")
Reads the posted fields.
BillingDetails—
billingErrorMessages(errors, labels?, format?)
Codes to messages; labels from a dictionary (tr.billingDetails) for other languages.
Partial<Record<BillingField, string>>—