KQ-1774 · TAX/PROFILE
Tax Profile
A billing-details form with a live invoice header beside it: every field a labelled native input in reading order with its error inline, the preview re-typesetting as you type and lighting the line of the field you are in. A well-formed tax ID runs a checking pulse along the field's lower edge while it is looked up; a registered number fills the legal name, which lifts out of the note under the field and glides into the invoice header on springs.glide, landing with a springs.flick settle and a wash of the accent while the Verified badge pops on springs.snap. Not-found numbers and an unanswering registry keep the entry with a note, a failed check digit is an inline error, and on a narrow container the preview folds away behind a toggle.
Billing details
Printed on every invoice from Waylight Labs Ltd
try gb 204 718 369 · or 990 317 427 for a registry that does not answer
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/tax-profile
Props
- fieldStyle
- "boxed" | "line" | "filled"
- default "boxed"
- How the inputs are drawn: bordered boxes, an underline only, or soft filled wells.
- previewStyle
- "classic" | "modern" | "compact"
- default "classic"
- The invoice header preview: seller left and title right, a large title with two blocks, or one tight strip.
- accent
- string
- default "var(--accent-bright)"
- Any CSS colour: focus edges, the checking pulse, the landing wash and the invoice rule.
- company
- string
- default ""
- The legal company name the form starts with.
- address
- TaxAddress
- default defaultTaxAddress
- The billing address the form starts with: { line1, line2, city, postalCode, country }.
- taxId
- TaxIdValue
- default { country: "GB", number: "" }
- The tax ID the form starts with; spaces and a repeated country prefix in the number are ignored.
- string
- default "billing@fernworks.studio"
- The billing email the form starts with.
- reference
- string
- default ""
- The purchase order reference the form starts with.
- values
- TaxProfileValues
- default —
- Controlled form values ({ company, taxId, email, address, reference }); when set, the starting-value props are ignored.
- onValuesChange
- (values: TaxProfileValues) => void
- default —
- Fires from every edit and from a registry fill, with all the values.
- countries
- TaxCountry[]
- default defaultTaxCountries
- Countries for the tax ID prefix and the address: { code, name }.
- seller
- TaxSeller
- default defaultTaxSeller
- Who issues the invoices, shown in the preview: { name, lines, taxId, email }.
- invoiceNumber
- string
- default "INV-2026-0418"
- The invoice number in the preview.
- now
- number
- default defaultTaxNow (17 Oct 2026)
- The current time in ms, the preview's issue date (read in UTC). Never read from the clock.
- lookup
- (taxId: string) => Promise<TaxLookupResult>
- default a seeded registry of four companies
- Looks a full tax ID up, e.g. "GB204718369"; a rejected promise reads as an unanswering registry.
- checkDelay
- number
- default 900
- How long the default lookup takes, in ms.
- onValidate
- (result: TaxLookupResult) => void
- default —
- Fires with every check outcome: valid (with the registered name), not-found, unreachable or invalid.
- onSave
- (values: TaxProfileValues) => void | Promise<void>
- default —
- Save was pressed with valid values; return a promise to show Saving… and its outcome. With errors, focus goes to the first invalid field instead.
- onCancel
- () => void
- default —
- Cancel was pressed; an uncontrolled form also returns to its last saved values.
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the saved details have arrived.
- onRetry
- () => void
- default —
- Try again was pressed after the details failed to load.
- height
- number
- default 540
- Height of the surface in px; its body scrolls inside.
- disabled
- boolean
- default false
- Nothing can be edited or saved.
- className
- string
- default —
- Classes for the outer surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| fieldStyle | "boxed" | "line" | "filled" | "boxed" | How the inputs are drawn: bordered boxes, an underline only, or soft filled wells. |
| previewStyle | "classic" | "modern" | "compact" | "classic" | The invoice header preview: seller left and title right, a large title with two blocks, or one tight strip. |
| accent | string | "var(--accent-bright)" | Any CSS colour: focus edges, the checking pulse, the landing wash and the invoice rule. |
| company | string | "" | The legal company name the form starts with. |
| address | TaxAddress | defaultTaxAddress | The billing address the form starts with: { line1, line2, city, postalCode, country }. |
| taxId | TaxIdValue | { country: "GB", number: "" } | The tax ID the form starts with; spaces and a repeated country prefix in the number are ignored. |
| string | "billing@fernworks.studio" | The billing email the form starts with. | |
| reference | string | "" | The purchase order reference the form starts with. |
| values | TaxProfileValues | — | Controlled form values ({ company, taxId, email, address, reference }); when set, the starting-value props are ignored. |
| onValuesChange | (values: TaxProfileValues) => void | — | Fires from every edit and from a registry fill, with all the values. |
| countries | TaxCountry[] | defaultTaxCountries | Countries for the tax ID prefix and the address: { code, name }. |
| seller | TaxSeller | defaultTaxSeller | Who issues the invoices, shown in the preview: { name, lines, taxId, email }. |
| invoiceNumber | string | "INV-2026-0418" | The invoice number in the preview. |
| now | number | defaultTaxNow (17 Oct 2026) | The current time in ms, the preview's issue date (read in UTC). Never read from the clock. |
| lookup | (taxId: string) => Promise<TaxLookupResult> | a seeded registry of four companies | Looks a full tax ID up, e.g. "GB204718369"; a rejected promise reads as an unanswering registry. |
| checkDelay | number | 900 | How long the default lookup takes, in ms. |
| onValidate | (result: TaxLookupResult) => void | — | Fires with every check outcome: valid (with the registered name), not-found, unreachable or invalid. |
| onSave | (values: TaxProfileValues) => void | Promise<void> | — | Save was pressed with valid values; return a promise to show Saving… and its outcome. With errors, focus goes to the first invalid field instead. |
| onCancel | () => void | — | Cancel was pressed; an uncontrolled form also returns to its last saved values. |
| status | "ready" | "loading" | "error" | "ready" | Whether the saved details have arrived. |
| onRetry | () => void | — | Try again was pressed after the details failed to load. |
| height | number | 540 | Height of the surface in px; its body scrolls inside. |
| disabled | boolean | false | Nothing can be edited or saved. |
| className | string | — | Classes for the outer surface. |