Skip to main content

FileUploader

FileUploader is a flexible file upload component that supports drag-and-drop, click-to-upload, keyboard interaction, file previews, and file removal. It works for both single and multiple file uploads with optional file type filtering.


Usage

Basic usage

import { FileUploader } from '@nofinite/nui';

<FileUploader onChange={(files) => console.log(files)} />;

Multiple files

<FileUploader multiple />

Controlled state

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

<FileUploader value={files} onChange={setFiles} />;

With restrictions

<FileUploader multiple accept="image/*" maxSize={2 * 1024 * 1024} />

Disabled

<FileUploader disabled />

Props

PropTypeDefaultDescription
valueFile[]Controlled files
defaultValueFile[][]Initial uncontrolled files
onChange(files: File[]) => voidChange callback
multiplebooleanfalseEnable multi-file aggregation
acceptstringNative accept filter
maxSizenumberMaximum file size in bytes
placeholderReactNodeDrag & drop files here, or click to browseDropzone text
disabledbooleanfalse Disable interaction
classNamestringRoot class override

Subcomponents

None exposed.


Variants

<FileUploader />
<FileUploader multiple />
<FileUploader disabled />
<FileUploader accept="image/*" />
<FileUploader maxSize={2097152} />

Available variants:

  • single (default)
  • multiple
  • disabled
  • type-restricted
  • size-restricted

Guidelines:

  • Use multiple for gallery or document uploads
  • Always provide accept when backend enforces MIME
  • Use size restriction to avoid unnecessary network cost

Sizes

Layout behavior:

ElementBehavior
Dropzonefull-width container
File listvertical stack
File itemauto height with truncation
Iconsfixed (16–24px)

Sizing is controlled via layout utilities and token spacing.


Shapes / Modes

Interaction states

  • Idle
  • Drag-over
  • File-selected
  • File-removed
  • Disabled

Data modes

  • Controlled
  • Uncontrolled
  • Multi-file aggregation
  • Size-filtered
  • MIME-filtered (native)

Design tokens / theming

Uses NUI tokens:

  • --nui-bg-surface
  • --nui-bg-subtle
  • --nui-bg-muted
  • --nui-fg-default
  • --nui-fg-subtle
  • --nui-fg-muted
  • --nui-border-default
  • --nui-border-hover
  • --nui-color-primary
  • --nui-color-danger
  • --nui-radius-*
  • --nui-space-*
  • --nui-text-sm
  • --nui-weight-medium
  • --nui-font-sans

Accessibility

Implemented:

  • Dropzone
    • role="button"
    • keyboard activation (Enter/Space)
    • focus-visible outline
    • aria-disabled
    • drag event semantics
  • Remove button
    • aria-label per file
  • Hidden input remains native for browser accessibility
  • Programmatic focus preserved

Limitations:

  • No upload progress semantics
  • No aria-live updates for file list
  • No error announcement for rejected files
  • Drag announcements depend on browser behavior

Animation model

  • File item pop-in via translateY + fade
  • Duration: 200ms
  • Drag-over visual highlight
  • Motion disabled with prefers-reduced-motion

No exit animation for removal.


Architectural notes

Key design decisions:

  • Input proxy pattern
  • Controlled/uncontrolled duality
  • Immutable file list replacement
  • Size validation pre-merge
  • Stable file key generation using name + size + lastModified
  • Drag state isolation
  • Event propagation control

Potential caveat:

  • File object identity used for removal (same file reselect handled via input reset)

Best practices

Do

  • Validate server-side regardless of client filters
  • Provide accept to guide user selection
  • Use multiple for batch uploads
  • Display upload progress externally if needed

Don’t

  • Depend on client MIME filtering for security
  • Upload extremely large files without chunking
  • Store File objects long-term in global state
  • Render heavy previews synchronously