React component for uploading images
npm install @leancodepl/image-uploaderReact component for image uploads.
``bash`
npm install @leancodepl/image-uploader
`bash`
yarn add @leancodepl/image-uploader
Manages image upload state and provides drag-and-drop functionality. Creates a complete image upload solution with file
validation, drag-and-drop support, optional cropping, and duplicate detection. Returns upload state and control
functions.
Parameters:
- value?: FileWithId[] - Current array of uploaded files with IDsaccept?: Accept
- - File types to accept (defaults to image types)cropper?: CropperConfig
- - Optional cropper configuration for image editingonError?: (errorCode: ErrorCode) => void
- - Callback for handling upload errorsonChange?: (files: FileWithId[]) => void
- - Callback when file list changes
Returns: Upload state and control functions including dropzone props
Uploads an image file using provided upload parameters. Handles file upload by calling the getUploadParams function to
retrieve upload configuration, then performs a fetch request to upload the file. Returns early if the image is already
uploaded.
Parameters:
- image: FileWithId | UploadedFileWithId - Image file with ID or already uploaded image with URLgetUploadParams: (image: FileWithId) => Promise
- - Function that returns upload
parameters (URI, method, headers) for the image
Returns: Promise resolving to uploaded image with URL
Throws: Error - When upload params are not defined, image is not defined, or upload fails
Root wrapper component for image upload functionality. Provides upload context to all child UploadImages components and
renders a div container. Must wrap all other UploadImages components to provide shared state.
Parameters:
- uploader: ReturnType - Upload state and functions from useUploadImages hookprops: HTMLAttributes
- - Additional HTML div attributes
Returns: JSX element wrapping children with upload context
Drag-and-drop zone component for file uploads. Creates an interactive drop zone with file input capabilities. Supports
both click-to-select and drag-and-drop file uploads. Provides drag state to children for visual feedback.
Parameters:
- children: ((props: UploadZoneChildProps) => ReactNode) | ReactNode - Content or render function receiving drag stateprops: HTMLAttributes
props
- - Additional HTML div attributes
Returns: JSX element with drag-and-drop upload functionality
Container component for displaying uploaded files. Renders a container for uploaded files and provides current file list
to children. Used to display and manage the collection of uploaded images.
Parameters:
- children: ((props: UploadFilesChildProps) => ReactNode) | ReactNode - Content or render function receiving filesprops: HTMLAttributes
array
- - Additional HTML div attributes
Returns: JSX element containing uploaded files
Individual file item component with preview and removal functionality. Displays a single uploaded file with preview
image generation and removal capability. Automatically generates image preview data and provides remove function to
children.
Parameters:
- children: ((props: UploadFileItemChildProps) => ReactNode) | ReactNode - Content or render function receiving file,file: FileWithId
preview, and remove function
- - File object with ID to displayprops: HTMLAttributes
- - Additional HTML div attributes
Returns: JSX element for individual file with preview and controls
Image cropper component with editing controls. Provides image cropping functionality with zoom, rotation, and crop area
controls. Processes cropped images and integrates with the upload state management.
Parameters:
- children: ((props: UploadImagesCropperEditorChildProps) => ReactNode) | ReactNode - Content or render function
receiving cropper controls
Returns: JSX element with cropper editing interface
Throws: Error - When cropper config is not defined in context
Visual editor component for image cropping. Renders the interactive crop editor interface using "react-easy-crop".
Provides visual feedback for crop area, zoom, and rotation adjustments.
Parameters:
- style?: CSSProperties - CSS style object, merged with default positioning stylesprops: HTMLAttributes
- - Additional HTML div attributes
Returns: JSX element with interactive crop editor
Throws: Error - When cropper config is not defined in context
The following types define the props passed to render functions in various components:
Props passed to the render function of UploadImages.Zone component.
Properties:
- isDragActive: boolean - True when files are being dragged over the drop zoneisFileDialogActive: boolean
- - True when the native file dialog is openisFocused: boolean
- - True when the drop zone is focused (keyboard navigation)
Props passed to the render function of UploadImages.Files component.
Properties:
- files?: FileWithId[] - Array of currently uploaded files with unique IDs
Props passed to the render function of UploadImages.File component.
Properties:
- file: FileWithId - The file object containing the original File and unique IDpreview?: string
- - Base64 data URL of the image preview (undefined while loading)remove: () => void
- - Function to remove this file from the upload list
Props passed to the render function of UploadImages.Cropper component.
Properties:
- zoom: number - Current zoom level (1.0 = no zoom)rotation: number
- - Current rotation angle in degreessetZoom: (zoom: number) => void
- - Function to update zoom levelsetRotation: (rotation: number) => void
- - Function to update rotation angleaccept: () => void
- - Function to accept the current crop and add to filesclose: () => void
- - Function to cancel cropping and close the editor
`typescript
import { useState } from "react";
import { UploadImages, useUploadImages, FileWithId } from "@leancodepl/image-uploader";
function BasicUpload() {
const [files, setFiles] = useState
const uploader = useUploadImages({
value: files,
onChange: setFiles,
onError: (error) => console.error("Upload error:", error),
accept: { "image/*": [".jpg", ".png", ".gif"] }
});
return (
{({ isDragActive }) => (
{isDragActive ? "Drop files here" : "Click or drag files to upload"}
)}
{file.originalFile.name}
{({ files }) => (
{files?.map(file => (
{({ preview, remove }) => (
)}
))}
)}
);
}
`
`typescript
import { tryUploadWithUploadParams } from "@leancodepl/image-uploader"
async function uploadToServer(image: FileWithId) {
try {
const uploadedImage = await tryUploadWithUploadParams(image, async img => {
// Get upload URL from your API
const response = await fetch("/api/upload-url", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
fileName: img.originalFile.name,
fileType: img.originalFile.type,
}),
})
const { uploadUrl, headers } = await response.json()
return {
uri: uploadUrl,
method: "PUT",
requiredHeaders: headers,
}
})
console.log("Upload successful:", uploadedImage.url)
return uploadedImage
} catch (error) {
console.error("Upload failed:", error)
throw error
}
}
`
`typescript
import { ErrorCode } from "@leancodepl/image-uploader"
function handleUploadError(errorCode: ErrorCode) {
switch (errorCode) {
case ErrorCode.FileTooLarge:
alert("File is too large. Please choose a smaller file.")
break
case ErrorCode.FileInvalidType:
alert("Invalid file type. Please upload an image file.")
break
case ErrorCode.TooManyFiles:
alert("Too many files selected. Please choose fewer files.")
break
default:
alert("An error occurred while uploading the file.")
}
}
const uploader = useUploadImages({
value: files,
onChange: setFiles,
onError: handleUploadError,
})
`
- Drag-and-Drop Support: Built on "react-dropzone" for intuitive file selection"react-easy-crop"
- Image Cropping: Optional cropping with zoom and rotation using
- File Validation: Automatic validation with customizable error handling
- Preview Generation: Automatic image preview generation for uploaded files
- Duplicate Detection: Prevents uploading the same file multiple times
- TypeScript Support: Full TypeScript definitions included
- Flexible UI: Render prop pattern for complete UI customization
- Server Integration: Helper utilities for uploading to any backend service
`typescript`
type CropperConfig = {
aspect: number // Aspect ratio (e.g., 16/9, 1, 4/3)
maxWidth?: number // Maximum output width in pixels
maxHeight?: number // Maximum output height in pixels
withRotation?: boolean // Enable rotation controls
withZoom?: boolean // Enable zoom controls
}
`typescript
// Accept only JPEG and PNG
const accept = {
"image/jpeg": [".jpg", ".jpeg"],
"image/png": [".png"],
}
// Accept all image types (default)
const accept = { "image/*": [] }
`
`typescript
import { useState } from "react";
import { UploadImages, useUploadImages, FileWithId } from "@leancodepl/image-uploader";
function CroppableUpload() {
const [files, setFiles] = useState
const uploader = useUploadImages({
value: files,
onChange: setFiles,
cropper: {
aspect: 16 / 9,
maxWidth: 800,
maxHeight: 450,
withRotation: true,
withZoom: true
}
});
return (
Drop images to crop
{({ zoom, rotation, setZoom, setRotation, accept, close }) => (
)}
{({ files }) => (
{files?.map(file => (
{({ preview, remove }) => (
)}
))}
)}
);
}
`
`typescript
import { tryUploadWithUploadParams } from "@leancodepl/image-uploader"
async function uploadToServer(image: FileWithId) {
try {
const uploadedImage = await tryUploadWithUploadParams(image, async img => {
// Get upload URL from your API
const response = await fetch("/api/upload-url", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
fileName: img.originalFile.name,
fileType: img.originalFile.type,
}),
})
const { uploadUrl, headers } = await response.json()
return {
uri: uploadUrl,
method: "PUT",
requiredHeaders: headers,
}
})
console.log("Upload successful:", uploadedImage.url)
return uploadedImage
} catch (error) {
console.error("Upload failed:", error)
throw error
}
}
`
`typescript
import { ErrorCode } from "@leancodepl/image-uploader"
function handleUploadError(errorCode: ErrorCode) {
switch (errorCode) {
case ErrorCode.FileTooLarge:
alert("File is too large. Please choose a smaller file.")
break
case ErrorCode.FileInvalidType:
alert("Invalid file type. Please upload an image file.")
break
case ErrorCode.TooManyFiles:
alert("Too many files selected. Please choose fewer files.")
break
default:
alert("An error occurred while uploading the file.")
}
}
const uploader = useUploadImages({
value: files,
onChange: setFiles,
onError: handleUploadError,
})
`
- Drag-and-Drop Support: Built on "react-dropzone" for intuitive file selection"react-easy-crop"
- Image Cropping: Optional cropping with zoom and rotation using
- File Validation: Automatic validation with customizable error handling
- Preview Generation: Automatic image preview generation for uploaded files
- Duplicate Detection: Prevents uploading the same file multiple times
- TypeScript Support: Full TypeScript definitions included
- Flexible UI: Render prop pattern for complete UI customization
- Server Integration: Helper utilities for uploading to any backend service
`typescript`
type CropperConfig = {
aspect: number // Aspect ratio (e.g., 16/9, 1, 4/3)
maxWidth?: number // Maximum output width in pixels
maxHeight?: number // Maximum output height in pixels
withRotation?: boolean // Enable rotation controls
withZoom?: boolean // Enable zoom controls
}
`typescript
// Accept only JPEG and PNG
const accept = {
"image/jpeg": [".jpg", ".jpeg"],
"image/png": [".png"],
}
// Accept all image types (default)
const accept = { "image/*": [] }
``