金額大寫輸入框(React)
輸入阿拉伯數字金額即時鏡射「新臺幣壹萬貳仟元整」大寫的 React 元件:千分位格式化、角分處理、一鍵複製,並具名匯出 toChineseUpper 轉換函式,支票、收據、合約、報價單都能直接用。
支票、收據、合約、報價單都要「金額大寫」。這個元件把數字輸入框(inputMode="decimal"、只收數字與一個小數點、最多兩位小數、輸入時自動千分位)和下方的大寫鏡射列綁在一起:每敲一個數字,「新臺幣壹萬貳仟元伍角整」逐字更新——只有變動的字會動,前綴與高位字保持不動;右側複製鈕一鍵複製全文,成功打勾。轉換規則寫成獨立的 toChineseUpper() 純函式,數字 零壹貳參肆伍陸柒捌玖、位 拾佰仟、節 萬億兆、小數 角分,連續零合併、節末零省略、「壹拾」保留,最大支援到兆。
npx shadcn@latest add https://webberui.com/r/chinese-amount-input.jsonPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<ChineseAmountInput />
安裝
npx shadcn@latest add https://webberui.com/r/chinese-amount-input.json或在 components.json 設定 registries 後,改用 @webberui/chinese-amount-input 安裝。
使用
import {
ChineseAmountInput,
toChineseUpper,
} from "@/components/ui/chinese-amount-input";
<ChineseAmountInput
label="報價總額(含稅)"
prefix="新臺幣"
onChange={(raw, { upper, formatted, amount }) => {
console.log(raw); // "12000.5"
console.log(formatted); // "12,000.5"
console.log(upper); // "新臺幣壹萬貳仟元伍角整"
console.log(amount); // 12000.5
}}
/>
// 轉換函式可單獨使用(例如列印支票或產生 PDF 時)
toChineseUpper(120000.5); // "壹拾貳萬元伍角整"
toChineseUpper("100000001", { prefix: "人民幣" }); // "人民幣壹億零壹元整"
toChineseUpper("1,680.32"); // "壹仟陸佰捌拾元參角貳分"(千分位逗號會被清掉)Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
value | string | number | — | 受控值:純數字字串(如 "12000.5")或 number;不提供時為非受控模式 |
defaultValue | string | number | "" | 非受控模式的初始值 |
onChange | (raw: string, meta: ChineseAmountChangeDetail) => void | — | 值變動時回呼:第一個參數為清洗後的純數字字串,第二個為大寫/千分位/數值 |
prefix | string | "新臺幣" | 大寫前綴幣別(如「人民幣」);傳空字串則不加 |
allowDecimal | boolean | true | 是否允許小數(角分);false 時只接受整數 |
max | number | — | 金額上限;超過時顯示錯誤提示並設定 aria-invalid(不會阻止輸入) |
label | string | "金額" | 欄位標籤文字 |
placeholder | string | "0" | 輸入框佔位提示 |
disabled | boolean | false | 停用輸入 |
name | string | — | 透傳給原生 input 的表單欄位名稱 |
className | string | — | 透傳到最外層容器 |
ChineseAmountChangeDetail
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
upper | string | — | 含 prefix 的完整大寫;超出「兆」時為 "" |
formatted | string | — | 千分位格式化後的顯示字串 |
amount | number | — | 解析後的數值;空值為 0 |
toChineseUpper(amount, opts?)
toChineseUpper(amount: number | string, opts?: ToChineseUpperOptions): string——接受 number 或字串(字串可含千分位逗號、全形數字)。空字串或非數字回傳 "";負數或整數超過 16 位(兆)丟出 RangeError。數字輸入四捨五入到分,字串輸入超過兩位小數則截斷(與輸入框行為一致)。
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
prefix | string | "" | 幣別前綴,如「新臺幣」「人民幣」 |
allowDecimal | boolean | true | 是否處理角分;false 時直接捨去小數部分 |
另外具名匯出 sanitizeAmount(raw, allowDecimal?)(清洗為純數字字串)、formatAmount(raw)(加千分位)與常數 MAX_AMOUNT_INT_DIGITS(16)。
細節
轉換規則對照(不帶 prefix):
| 輸入 | 輸出 |
|---|---|
0 | 零元整 |
10 | 壹拾元整 |
100 | 壹佰元整 |
1005 | 壹仟零伍元整 |
10500 | 壹萬零伍佰元整 |
120000.5 | 壹拾貳萬元伍角整 |
1000000 | 壹佰萬元整 |
100000001 | 壹億零壹元整 |
1.05 | 壹元零伍分 |
1680.32 | 壹仟陸佰捌拾元參角貳分 |
- 「壹拾」不省略為「拾」(
12→ 壹拾貳):金額大寫的目的是防塗改,與口語「十二」不同 - 有角無分寫「元X角整」,有分無角寫「元零X分」,兩者都有寫「元X角X分」
- 整數最多 16 位(9999 兆餘),再往上輸入框會顯示「超出支援範圍」錯誤並設
aria-invalid;設定max時超過上限同樣提示,但不阻止輸入,讓使用者自己修 - 輸入框接受全形數字與全形句點(中文輸入法下常誤打),會自動轉為半形;千分位逗號在貼上時會被清掉,顯示時再補回
- 插入千分位逗號後游標維持在原本的數字位置,不會跳到行尾
可及性
- 實際輸入為單一原生
input(inputMode="decimal"),行動裝置會叫出數字鍵盤;aria-describedby同時指向大寫鏡射列與提示訊息 - 大寫鏡射列是
aria-live="polite"區域,逐字動畫一律aria-hidden,螢幕閱讀器只會朗讀完整字串(如「新臺幣壹萬貳仟元整」) - 超出範圍或超過
max時設定aria-invalid,錯誤訊息置於role="status"區域 - 複製鈕為
type="button",帶aria-label(複製成功後改為「已複製大寫金額」),支援鍵盤操作與focus-visible外框 - 使用者系統開啟「減少動態效果」時,大寫改為直接替換文字,不做逐字淡入/滑動;複製圖示切換與訊息切換也不做動畫