跳至主要内容
💬 回報這一頁

資料表標準

問題

表格是後台系統的主體,也是最容易長歪的地方。

手刻三張表之後,你會得到三種搜尋框位置、三種排序箭頭、三種「查無資料」文案。 更糟的是三種合計邏輯——其中一種只加總當頁,而且沒有人發現。

做法:一份欄位設定驅動全部

{
key: "amount",
header: "金額",
numeric: true, // 右對齊 + 等寬
cell: (r) => formatMoney(r.amount),
sortValue: (r) => r.amount, // 有才可排序
filterText: (r) => String(r.amount), // 參與關鍵字搜尋
filter: "range", // 單欄篩選型態
total: (rows) => formatMoney(sum(rows)),
freeze: true, // 凍結首欄
}

上面那份設定產出的,就是下面這張表——九條標準全部由欄位設定驅動,沒有一條是另外寫的

試試搜尋、點欄頭排序、點漏斗篩選、拖曳欄邊界
R-2406戊單位戊案 整併12$268,800已確認
R-2403丙單位丙案 初版6$213,000已確認
R-2402乙單位乙案 追加規格 這一筆刻意加長,用來示範欄位截斷與可調欄寬40$156,400已確認
R-2407乙單位乙案 附屬項目300$91,200已作廢
R-2401甲單位甲案 第一階段120$84,000已完成
合計5,558$893,700
這是真元件

文件站直接編譯 packages/react 的原始碼,不是截圖。 逐條 API 說明在 DataTable 元件頁

九條標準

#標準為什麼
1關鍵字搜尋橫跨所有文字欄使用者第一個動作永遠是「找那筆」
2單欄篩選:文字包含/數值範圍/多選「找」和「篩」是不同任務
3同欄多條件 OR、跨欄 AND符合直覺:同一欄想看多個值,不同欄要同時滿足
4排序三態:無 → 大到小 → 小到大第一下的意圖幾乎都是「誰最多」;要能回到原始順序
5門檻式分頁:沒超過一頁就不顯示分頁器「第 1 頁 / 共 1 頁」是噪音
6合計算篩選後全部,不是當頁只算當頁是對帳災難
7凍結首欄20 欄的表水平捲動後,不知道這列是誰
8匯出跟著畫面(篩選+排序後)「我明明篩好了,匯出卻是全部」
9空狀態分辨「沒資料」與「篩不到」兩者的下一步完全不同

三種列狀態要真的分得開

資料表是這套系統最吃重的畫面,而「我指在哪一列」「我選了哪幾列」是它最基本的兩個問題。 改版前這兩件事實測是看不出來的:

改版前(淺色 ΔE00)現在
一般 → hover1.63.0
hover → 已選1.67.8

原因不是顏色選得不好,是機制:舊做法 hover 用 --accent、已選用 --muted, 而這兩個 token 的值相同——斑馬列本來就是那個顏色。現在三種狀態都疊一層 currentColor(6% / 14% / 20%),所以「深了一階」在一般列與斑馬列上一樣成立。

兩條連帶規則:

  • 已選的列,次要文字改用正文色。 20% 疊加之後 --muted-foreground 掉到 2.77:1。 TableRowdata-state="selected" 時直接把 --muted-foreground 重新定義成 --foreground,列裡所有吃這個變數的東西一次跟上。
  • 多選時 checkbox 才是主要線索,底色是輔助。一次選 20 列時, 底色若獨自扛完整訊息就會變成整片彩色——顏色永遠不是唯一線索。

門檻與量測方法見互動狀態的顏色邏輯

加分項:十字對準與可調欄寬

  • 十字對準:指到哪一格就 highlight 整行整列。20 欄的表靠這個才不會看錯行。
  • 可調欄寬:拖曳邊界、雙擊自適應。中文品名長度差異極大,固定欄寬一定有人不滿意。

取捨

代價:欄位設定比手刻 <td> 抽象。 第一張表確實比較慢。

回本點大約在第二張表。而且真正的收益不是省時間,是「所有表格行為一致」—— 使用者學會一張,就會用全部。

反例

✅ 這樣做

凡是「使用者要在裡面找某一筆」的清單,一律用標準資料表。

🚫 不要這樣

不要因為「這張表只有 5 筆」就手刻。三個月後它會有 500 筆, 而那時候補搜尋排序的成本比一開始就用高得多。

✅ 這樣做

合計列傳入的是篩選後的全部列

🚫 不要這樣

不要傳當頁的列。這個錯誤不會拋例外、不會有紅字, 只會讓某個人在某個月的對帳中崩潰。

實作見 DataTable