@files-ui/react
v2.1.0
Published
UI components for file uploads with React js
Maintainers
Readme
✨ What's New in v2.1.0
🎉 Major update with powerful new capabilities!
🎨 Material Design Icons
Beautiful Material Design selection checkboxes with full dark mode support
<FileMosaic
{...file}
selectable
selected
darkMode
/>🖼️ Image Editing
Built-in edit icon for image files with callback support
<FileMosaic
{...file}
onEdit={handleEdit}
preview
/>🔌 Optional Plugin Ecosystem
Extend functionality without bloating your bundle:
- @files-ui/crop (~11KB) — Interactive image cropping
- @files-ui/compress (~8KB) — Image optimization
🚀 Quick Start
Installation
npm install @files-ui/react
# or
yarn add @files-ui/reactBasic Usage
import { Dropzone, FileMosaic } from "@files-ui/react";
import { useState } from "react";
export default function App() {
const [files, setFiles] = useState([]);
return (
<Dropzone onChange={setFiles} value={files}>
{files.map((file) => (
<FileMosaic key={file.id} {...file} preview />
))}
</Dropzone>
);
}Live Demos:
| Demo | Link |
|------|------|
| Basic Sample 🍰 | |
| Advanced Sample 🔨 |
|
💎 Key Features
📤 Upload & Validation
- ✅ Drag & Drop — Intuitive file upload
- ✅ File Validation — Type, size, custom validators
- ✅ Upload Progress — Real-time upload tracking
- ✅ Chunked Upload — Large file support
- ✅ Server Actions — Next.js 16+ native support
🎨 UI Components
- ✅ Multiple Layouts — Grid (FileMosaic) & Card (FileCard)
- ✅ Material Icons — Beautiful Material Design icons
- ✅ Dark Mode — Built-in theme support
- ✅ Selection API — Multi-select with checkboxes
- ✅ Preview — Image and video fullscreen preview
- ✅ Avatar — Profile image picker
🔧 Developer Experience
- ✅ TypeScript — Full type definitions
- ✅ Headless —
useFilesUI()hook for custom UIs - ✅ Zero Dependencies — Core has no external deps
- ✅ RSC Compatible — Next.js App Router ready
- ✅ Framework Agnostic — Works with any React setup
📚 Main Components
| Component | Purpose | Key Props |
|-----------|---------|-----------|
| <Dropzone/> | Main upload area | onChange, value, accept, maxFileSize |
| <FileMosaic/> | Grid file display | preview, onDelete, onEdit, selectable |
| <FileCard/> | Card file display | elevation, preview, darkMode |
| <Avatar/> | Profile image picker | src, alt, onChange |
| <FileInputButton/> | Button uploader | onChange, accept |
| <FullScreen/> | Modal preview | open, onClose |
🎯 Common Use Cases
import { Dropzone, FileMosaic } from "@files-ui/react";
import { CropDialog, useCropDialog } from "@files-ui/crop/react";
import { compressImage } from "@files-ui/compress";
function ImageUploader() {
const [files, setFiles] = useState([]);
const { cropFile, openCrop, closeCrop, handleCropComplete } = useCropDialog({
onComplete: async (croppedFile) => {
// Compress after crop
const compressed = await compressImage(croppedFile, {
maxWidthOrHeight: 1920,
quality: 0.85
});
updateFile(compressed);
}
});
return (
<>
<Dropzone onChange={setFiles} value={files}>
{files.map(file => (
<FileMosaic key={file.id} {...file} onEdit={openCrop} />
))}
</Dropzone>
{cropFile && (
<CropDialog
file={cropFile}
onComplete={handleCropComplete}
onCancel={closeCrop}
/>
)}
</>
);
}import { Dropzone, FileMosaic, FilesUiProvider } from "@files-ui/react";
// Global dark mode
function App() {
return (
<FilesUiProvider config={{ darkMode: true }}>
<Dropzone onChange={setFiles} value={files}>
{files.map(file => (
<FileMosaic key={file.id} {...file} />
))}
</Dropzone>
</FilesUiProvider>
);
}
// Per-component dark mode
<FileMosaic {...file} darkMode />
<FileCard {...file} darkMode />function FileSelector() {
const [files, setFiles] = useState([]);
const [selected, setSelected] = useState(new Set());
const handleSelect = (fileId, isSelected) => {
setSelected(prev => {
const next = new Set(prev);
isSelected ? next.add(fileId) : next.delete(fileId);
return next;
});
};
return (
<Dropzone onChange={setFiles} value={files}>
{files.map(file => (
<FileMosaic
key={file.id}
{...file}
selectable
selected={selected.has(file.id)}
onSelect={handleSelect}
/>
))}
</Dropzone>
);
}// app/actions/upload.ts
"use server";
export async function uploadFile(formData: FormData) {
const file = formData.get("file") as File;
// Process file...
return { success: true, message: `Uploaded ${file.name}` };
}
// app/uploader.tsx
"use client";
import { Dropzone } from "@files-ui/react/client/dropzone";
import { uploadFile } from "./actions/upload";
export function Uploader() {
return <Dropzone action={uploadFile} />;
}import { useFilesUI } from "@files-ui/react";
function CustomUploader() {
const { files, uploadFiles, getDragHandlers, getInputProps } = useFilesUI({
accept: "image/*",
maxFileSize: 5 * 1024 * 1024,
url: "/api/upload"
});
return (
<div {...getDragHandlers()} className="my-dropzone">
<input {...getInputProps()} />
<button onClick={() => uploadFiles()}>
Upload {files.length} files
</button>
</div>
);
}📖 Documentation
- 📚 Complete Documentation — Component API, guides, examples
- 🎨 Storybook — Interactive component playground
- 📝 Changelog — Release history
- 🔗 TypeScript Definitions — Full type support
🖼️ More Previews
🌐 Browser Support
| Browser | Version | |---------|---------| | Chrome | ✅ Latest | | Firefox | ✅ Latest | | Safari | ✅ 14+ | | Edge | ✅ Latest | | Mobile | ✅ iOS 14+, Android Chrome |
🤝 Contributing
We welcome contributions! See CONTRIBUTING.md for guidelines.
Ways to contribute:
- 🐛 Report bugs via GitHub Issues
- ✨ Suggest features
- 📝 Improve documentation
- 🔧 Submit pull requests
💬 Community & Support
- 💡 GitHub Discussions — Ask questions
- 📧 Email Support — Get help
- 🐛 Issue Tracker — Report bugs
⭐ Show Your Support
If Files UI helped your project:
- ⭐ Star us on GitHub
- 🐦 Share on social media
- 💬 Tell your developer friends
- 📝 Write about it on your blog
It really helps us grow! 🙏
📄 License
MIT License — See LICENSE for details.
© 2024 Files UI Contributors
