Taiwan Business Tax ID Input
A React component that validates Taiwan's 8-digit business tax ID (Uniform Number) in real time — it implements the 2023 check-digit algorithm (weights 1,2,1,2,1,2,4,1, including the special case where the 7th digit is 7) and shows pass/fail with animated feedback as you type.
This implements the Ministry of Finance's published check-digit algorithm for the Taiwan business tax ID: each digit is multiplied by the weights 1,2,1,2,1,2,4,1, the digit sums of those products are added up, and the total passes if it is divisible by 5 (the rules in force since April 2023, backwards compatible with older tax IDs), with the special case where the 7th digit is 7 handled as well. Validation runs the moment 8 digits are entered — a green check pulses on success, and the whole row shakes with a red outline and an explanation on failure. Pasting a string with noise in it is cleaned automatically down to the digits.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add tax-id-input.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<TaxIdInput/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/tax-id-input.en.jsonOr, once registries are configured in components.json, install it as @webberui/tax-id-input.
Usage
import { TaxIdInput, validateTaxId } from "@/components/ui/tax-id-input";
<TaxIdInput
label="Uniform Number"
onChange={(value) => console.log(value)}
onValid={(ok, value) => ok && console.log(`${value} can be invoiced`)}
/>
// The validator can be used on its own (handy for one more check before form submission)
validateTaxId("12345675"); // true (an algorithm test number, not a real company)
validateTaxId("12345678"); // falseProps
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled value (digits only, at most 8); when omitted the component is uncontrolled |
defaultValue | string | "" | Initial value in uncontrolled mode |
onChange | (value: string) => void | — | Callback when the value changes; the argument is the cleaned digits-only string |
onValid | (valid: boolean, value: string) => void | — | Callback when 8 digits have been entered and validation completes; it fires once per value |
label | string | "Uniform Number" | Field label text |
disabled | boolean | false | Disable the input |
name | string | — | Form field name forwarded to the native input |
className | string | — | Forwarded to the outermost container |
validateTaxId(input), sanitizeTaxId(raw), and the TaxIdStatus type are also named exports, so the same validation logic can be reused at the form layer.
Accessibility
- The real input is carried by a single native
input(inputMode="numeric",pattern="[0-9]*"); the 8 visual boxes are presentational only and markedaria-hidden, so keyboard behavior and the mobile numeric keypad behave exactly like an ordinary input - The validation message sits in an
aria-live="polite"region, so state changes are read out by screen readers;aria-invalidis set at the same time when validation fails - When the user has "reduce motion" enabled at the system level, the shake, pulse, and caret blink animations are disabled and only the color and text feedback remains