file-uploader.tsx
Overview
file-uploader.tsx is a React client-side component file that implements a versatile and user-friendly file uploader UI. It supports drag-and-drop file selection, file preview (especially for images), file removal, upload progress visualization, and customizable file acceptance criteria (such as file types, max file size, and max file count). The component integrates with external upload handlers and provides user feedback through toast notifications.
Key features include:
Drag-and-drop support via
react-dropzone.Preview thumbnails for image files.
File list management with add/remove capabilities.
Upload progress bars per file.
Configurable acceptance criteria (file types, max size, max count).
Localization support via
react-i18next.Accessibility and responsive design considerations.
This component is suitable for use in web applications that require users to upload files with real-time feedback and validation.
Detailed API Documentation
Utility Type Guard
isFileWithPreview(file: File): file is File & { preview: string }
Type guard that checks if a given File object has a preview property of type string. This is used internally to distinguish files with a generated preview URL (typically images).
Components
FilePreview
interface FilePreviewProps {
file: File & { preview: string };
}
function FilePreview({ file }: FilePreviewProps): JSX.Element
Description:
Renders a thumbnail preview of the file if it is an image (file.type starts with "image/"). For non-image files, it renders a generic file icon.
Parameters:
file: AFileobject extended with apreviewURL string.
Returns: JSX element showing either an image thumbnail or a file icon.
Usage Example:
<FilePreview file={fileWithPreview} />
FileCard
interface FileCardProps {
file: File;
onRemove: () => void;
progress?: number;
}
function FileCard({ file, progress, onRemove }: FileCardProps): JSX.Element
Description:
Displays a card UI for a single file in the upload list. Shows file name, size, optional upload progress bar, and a remove button.
Parameters:
file: TheFileobject to display.onRemove: Callback invoked when the user clicks the remove button.progress(optional): A number representing upload progress percentage (0 - 100).
Returns: JSX element representing the file card UI.
Usage Example:
<FileCard
file={file}
progress={uploadProgress[file.name]}
onRemove={() => handleRemoveFile(index)}
/>
FileUploader
interface FileUploaderProps extends React.HTMLAttributes<HTMLDivElement> {
value?: File[];
onValueChange?: (files: File[]) => void;
onUpload?: (files: File[]) => Promise<void>;
progresses?: Record<string, number>;
accept?: DropzoneProps['accept'];
maxSize?: DropzoneProps['maxSize'];
maxFileCount?: DropzoneProps['maxFiles'];
multiple?: boolean;
disabled?: boolean;
description?: string;
}
function FileUploader(props: FileUploaderProps): JSX.Element
Description:
Main file uploader component that provides drag-and-drop file selection, file list display with previews, upload progress, and file removal. It handles validation against file count and size, accepts customizable file types, and integrates with external upload logic.
Props:
Prop | Type | Default | Description | Example |
|---|---|---|---|---|
|
|
| Controlled value representing the current files selected/uploaded. |
|
|
|
| Callback fired when the selected files change. |
|
|
|
| Async callback triggered when files are dropped/added, to handle upload logic externally. |
|
|
|
| Object mapping file names to their upload progress percentages (0-100). |
|
|
|
| Accepted MIME types or file extensions for upload. |
|
|
|
| Maximum file size allowed in bytes. |
|
|
|
| Maximum number of files allowed to upload. |
|
|
|
| Enable multiple file selection. |
|
|
|
| Disable the uploader UI. |
|
|
|
| Custom description text shown below the dropzone area. |
|
Returns: JSX element representing the whole file uploader UI.
Usage Example
import { FileUploader } from './file-uploader';
function MyUploadComponent() {
const [files, setFiles] = React.useState<File[]>([]);
const [progresses, setProgresses] = React.useState<Record<string, number>>({});
async function handleUpload(filesToUpload: File[]) {
// Example upload logic that updates progress
for (const file of filesToUpload) {
// Simulate upload with progress updates
for (let progress = 0; progress <= 100; progress += 10) {
setProgresses((prev) => ({ ...prev, [file.name]: progress }));
await new Promise((r) => setTimeout(r, 100));
}
}
}
return (
<FileUploader
value={files}
onValueChange={setFiles}
onUpload={handleUpload}
progresses={progresses}
accept={{ 'image/*': [] }}
maxSize={5 * 1024 * 1024} // 5MB max size
maxFileCount={3}
multiple
description="Drag & drop up to 3 images or click to select."
/>
);
}
Implementation Details and Algorithms
File Preview Generation:
When files are dropped or selected, the component generates preview URLs usingURL.createObjectURL(file). This allows instant local previews of image files without uploading. On component unmount, all generated object URLs are revoked to free memory.File Validation:
The component usesreact-dropzone's validation for accepted file types, max size, and max files. Additional validation enforces the custom maximum file count and single file mode with toast error notifications.Controlled vs Uncontrolled State:
Uses a custom hookuseControllableStateto manage the files list either as a controlled component (withvalueandonValueChangeprops) or uncontrolled internally.Upload Handling:
When new files are accepted, if anonUploadcallback is provided, it is called with the updated file list. Upload progress is handled externally and passed in via theprogressesprop. The component displays a toast promise to indicate loading, success, or error states during upload.Accessibility & UX:
The file removal buttons have screen-reader-only text for accessibility.
The drag area changes style when active and disables interaction when disabled or max files reached.
Preview images have
loading="lazy"for performance optimization.
Internationalization:
Usesreact-i18next(useTranslation) for localized text strings for upload instructions.
Interaction with Other Parts of the System
UI Components:
Utilizes shared UI components such asButton,Progress, andScrollAreafrom the application's UI library (@/components/ui/*).Hooks:
Leverages a customuseControllableStatehook (@/hooks/use-controllable-state) for managing controlled/uncontrolled state behavior.Utilities:
Uses utility functionscn(className concatenation) andformatBytes(human-readable file size formatting) from@/lib/utils.Third-Party Libraries:
react-dropzonefor drag-and-drop file selection and validation.lucide-reactfor vector icons.sonnerfor toast notifications.react-i18nextfor localization.
File Upload Logic:
The actual file upload process is intended to be implemented outside this component and integrated via theonUploadprop. This allows the component to be flexible and reusable across different backend upload strategies.
Visual Diagram
componentDiagram
component FileUploader {
+value?: File[]
+onValueChange?: (files: File[]) => void
+onUpload?: (files: File[]) => Promise<void>
+progresses?: Record<string, number>
+accept?: DropzoneProps['accept']
+maxSize?: number
+maxFileCount?: number
+multiple?: boolean
+disabled?: boolean
+description?: string
}
component Dropzone
component FileCard {
+file: File
+progress?: number
+onRemove: () => void
}
component FilePreview {
+file: File & { preview: string }
}
FileUploader --> Dropzone : renders
FileUploader --> FileCard : renders for each file
FileCard --> FilePreview : renders if image
Summary
file-uploader.tsx is a robust React component designed for intuitive file uploading with drag-and-drop support, previews, progress tracking, and user notifications. It is highly configurable and designed to integrate seamlessly with various upload backends and UI themes, making it a valuable asset in modern web applications requiring file input functionality.