react-image-lab
v1.0.2
Published
A minimal, modern, TypeScript-first React 18+ component library for image uploading, camera capture, cropping, zooming, rotating, and resizing.
Maintainers
Readme
🚀 Live Demo
Try it out on CodeSandbox (Coming Soon)
⚡ Why this library?
Building a robust image upload and cropping experience usually requires stitching together multiple libraries (one for UI, one for the cropper, one for canvas manipulation, one for camera access).
React Image Lab solves this by providing a unified, drop-in modal that handles the entire pipeline:
- Acquisition: Drag & Drop, File Browse, or Native Device Camera.
- Editing: High-performance zooming, rotation, and aspect-ratio locked cropping.
- Processing: Client-side canvas resizing and format conversion.
Comparison
| Feature | react-image-lab | react-easy-crop | react-avatar-editor |
| ------------------- | --------------------------------------- | -------------------------- | -------------------------- |
| UI Included? | ✅ Yes (Beautiful Modal & Controls) | ❌ No (Bring your own UI) | ❌ No (Canvas only) |
| Camera Support | ✅ WebRTC built-in | ❌ No | ❌ No |
| Client Resizing | ✅ Built-in (width/height/quality) | ❌ No | ❌ No |
| Styling | ✅ Tailwind-friendly, auto-injected CSS | ⚠️ Manual styling required | ⚠️ Manual styling required |
✨ Features
- All-in-One UI Modal: Fully fully built, accessible modal handling the entire flow.
- Camera Integration: Seamlessly switch to front/back cameras to snap photos.
- Advanced Cropping: Circular masks, fixed aspect ratios (1:1, 16:9, etc), zoom, and 360° rotation.
- Client-Side Compression: Resizes and compresses images to WebP/JPEG/PNG before uploading, saving bandwidth.
- TypeScript First: Written in strict TypeScript with comprehensive type definitions.
- Zero Configuration: CSS is automatically injected. Works flawlessly with SSR frameworks like Next.js.
- Performance Optimized: Built with strict React memoization to prevent canvas re-renders.
📦 Installation
npm install react-image-lab react-easy-cropNote: react-easy-crop is a peer dependency used internally for its robust touch/mouse mapping engine.
💻 Usage
Drop the ImageStudio component anywhere in your app. It manages its own portal, so it will always render on top of your application layout safely.
import React, { useState } from "react";
import { ImageStudio } from "react-image-lab";
export default function App() {
const [isOpen, setIsOpen] = useState(false);
const handleSave = (file: File, objectUrl: string) => {
console.log("Exported File:", file);
// Example: Upload to your server
// const formData = new FormData();
// formData.append('avatar', file);
// await fetch('/api/upload', { method: 'POST', body: formData });
};
return (
<div>
<button onClick={() => setIsOpen(true)}>Upload Profile Picture</button>
{isOpen && (
<ImageStudio
isOpen={isOpen}
onClose={() => setIsOpen(false)}
onSave={handleSave}
title="Update Avatar"
aspectRatio={1} // Force 1:1 square crop
circularCrop={true} // Display circular clipping mask
maxWidth={800} // Downscale to max 800px width
exportFormat="image/webp" // Export as modern WebP
quality={0.9} // 90% compression quality
theme="dark" // Easily switch between "light" and "dark"
accentColor="#10b981" // Override the default Indigo to custom Emerald
/>
)}
</div>
);
}⚙️ Props API
| Prop | Type | Default | Description |
| ----------------- | --------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------- |
| isOpen | boolean | Required | Controls visibility of the studio modal. |
| onClose | () => void | Required | Triggered when the user clicks Cancel or the backdrop. |
| onSave | (file: File, url: string) => void | undefined | Fired when export logic finishes successfully. returns the native File and a temporary object url. |
| title | string | "React Image Studio" | The heading on top of the modal. |
| aspectRatio | number \| undefined | undefined | Fixed aspect ratio map for Cropper (e.g 16/9, 1). If omitted, user can crop freely or select from a dropdown. |
| circularCrop | boolean | false | Restricts the visual crop mask to a circular clipping path (perfect for avatars). |
| maxWidth | number | undefined | Maximum width (px) of the final exported image. Preserves proportions. |
| maxHeight | number | undefined | Maximum height (px) of the final exported image. Preserves proportions. |
| quality | number | 0.95 | Quality ratio (0.0 - 1.0) applied to WebP/JPEG exports. |
| exportFormat | 'image/jpeg' \| 'image/png' \| 'image/webp' | 'image/jpeg' | Desired final Mime type format for HTML5 canvas output. |
| acceptedFormats | string | "image/*" | Accept attribute pattern for HTML <input type="file">. |
| maxFileSizeMB | number | 5 | Rejects uploaded files larger than this size limit (in Megabytes). |
| onError | (error: string) => void | undefined | Callback for internal errors (e.g. file too large, canvas crash). |
| theme | 'light' \| 'dark' | 'light' | Toggles the entire UI to use the Light or Dark mode variable palette. |
| accentColor | string | undefined | Provide any valid CSS color (HEX, RGB) to globally inject an override for the primary accent color. |
♿ Accessibility & UI
- ARIA Compliant: Modal uses standard
role="dialog"andaria-modal="true". Focus is trapped inside the modal while open, and background scrolling is locked. - Tailwind Friendly: Uses minimal native CSS with
ris-prefixes to prevent global namespace pollution. Buttons inherit standard utility styles cleanly without requiring a massive CSS framework.
🗺️ Roadmap
- [ ] Add explicit i18n support for translated UI strings.
- [ ] Allow passing custom CSS classes for inner components (Uploader, Buttons).
- [ ] Add optional image filters (e.g., Grayscale, Sepia) before export.
- [ ] Implement
framer-motionas an optional dependency for spring animations.
🛠️ Contributing
Contributions are always welcome!
- Fork the project
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📄 License
Distributed under the MIT License. See LICENSE for more information.
