Stepwise UI

File Uploader

A file picker with drag-and-drop, in a dropzone variant and a compact one. The component is purely presentational - you own progress tracking and the upload logic, passing file entries back in via files.

Installation

npx stepwise-ui add file-uploader

Dropzone

One drop target, not two widgets glued together - the dashed box is the Folder's own hit area. Hover, tap, or focus it to see what's inside - each card shows its name on hover, and its own remove button, confirmed through the Modal component before anything's actually gone. Try it - drag one of the files below onto it.

Drag one onto the folder

Roadmap.pdf
Brand-assets.zip
Meeting-notes.docx

Drag & drop files, or

import { FileUploader, type FileEntry } from '@/components/stepwise/file-uploader'

const [files, setFiles] = useState<FileEntry[]>([])

const onFiles = (incoming: File[]) => {
  setFiles(prev => [
    ...prev,
    ...incoming.map(f => ({ id: crypto.randomUUID(), file: f })),
  ])
}

// default variant - a real Folder as the drop target. Drag files onto it
// or click "Select" to browse; it tilts open on hover and shows progress
// both on the pocket and on each file's own card as it peeks out. Hovering
// a card shows its name - click the × on one to remove it (confirmed via
// the Modal component before it's actually gone).
<FileUploader
  files={files}
  onFiles={onFiles}
  onRemove={id => setFiles(prev => prev.filter(f => f.id !== id))}
  maxMB={10}
/>

Compact

The same Button with slideIcon you'll find everywhere else - it's also its own drop target. Drag a file over it and the icon swaps to an incoming arrow; the label answers with the file count once something's selected.
<FileUploader
  variant="compact"
  files={files}
  onFiles={onFiles}
  onRemove={onRemove}
/>

Props

PropTypeDescription
variant
"dropzone" | "compact"
Visual layout. Default "dropzone".
color
string
"dropzone" variant only - folder body color. Default: amber (#f5d98b).
files
FileEntry[]
Controlled file list with optional progress.
onFiles
(files: File[]) => void
Called with accepted File objects. Caller tracks progress.
onRemove
(id: string) => void
Called after the remove is confirmed in the Modal.
accept
string
MIME types or file extensions (e.g. ".pdf,.docx").
multiple
boolean
Allow multiple files. Default true.
maxMB
number
Silently skip files over this size (MB).