WebberUI

File Dropzone

拖放上傳區:磁吸虛線邊框朝游標偏移、跑馬燈流動,檔案列表附環形進度。

載入預覽⋯

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

0.12
<FileDropzone />

安裝

npx shadcn@latest add https://webberui.com/r/file-dropzone.json

或在 components.json 設定 registries 後,改用 @webberui/file-dropzone 安裝。

安裝依賴後,從 registry JSON(/r/file-dropzone.jsonfiles[0].content)複製 file-dropzone.tsx 原始碼到你的 components/ui/ 目錄:

npm install motion lucide-react clsx tailwind-merge

使用

import { FileDropzone } from "@/components/ui/file-dropzone";

<FileDropzone
  accept="image/*,.pdf"
  maxFiles={4}
  maxSize={10 * 1024 * 1024}
  onFilesAdded={(files) => console.log(files)}
/>

接上真實上傳

未提供 upload 時元件以模擬進度展示動畫;接上後端時傳入非同步函式並回報進度:

<FileDropzone
  upload={async (file, onProgress) => {
    await uploadToServer(file, {
      onUploadProgress: (e) => onProgress(e.loaded / e.total),
    });
  }}
/>

resolve 顯示成功打勾,reject 顯示失敗狀態。

Props

Prop型別預設值說明
onFilesAdded(files: File[]) => void檔案通過驗證並加入清單時觸發
upload(file: File, onProgress: (p: number) => void) => Promise<void>自訂上傳邏輯,onProgress 回報 0–1;未提供時模擬進度
onRemove(file: File) => void從清單移除檔案時觸發
onReject(file: File, reason: "type" | "size" | "count") => void檔案未通過驗證時觸發
acceptstring接受的檔案型別(同原生 accept),拖放也會套用驗證
multiplebooleantrue允許多檔;false 時新檔案取代舊檔案
maxFilesnumber清單檔案數量上限
maxSizenumber單一檔案大小上限(bytes)
strengthnumber0.12磁吸強度,邊框偏移量 = 游標相對中心距離 × strength
labelstring"拖放檔案到這裡,或點擊選取"放置區主要文字
disabledbooleanfalse停用整個放置區

細節

  • 磁吸邊框:拖曳懸停時,虛線邊框以 spring 朝游標方向偏移(上限 10px)並輕微放大,同時虛線以跑馬燈方式流動
  • 拖曳進出子元素會連發 dragenterdragleave,內部以深度計數避免邊框狀態閃爍
  • 進度環以 SVG stroke-dashoffset 搭配 spring 平滑推進,完成後彈出打勾、失敗顯示警示
  • accept 驗證支援副檔名(.pdf)、萬用字元(image/*)與完整 MIME,拖放與點選皆套用
  • 檔案選取後會清空 input value,同一檔案可重複選取

可及性

  • 放置區為 role="button",可 Tab 聚焦,Enter/Space 開啟檔案選取器
  • 進度環帶 role="progressbar"aria-valuenow,成功/失敗圖示有對應 aria-label
  • 上傳中的檔案數量透過 aria-live="polite" 播報給螢幕閱讀器
  • 使用者系統開啟「減少動態效果」時,磁吸偏移、跑馬燈與進出場動畫停用,進度環直接跳至目前值

On this page