# File Upload URL: https://ark-ui.com/docs/components/file-upload Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/file-upload.mdx A component that is used to upload multiple files. --- ## Anatomy ```tsx ``` ## Examples **Example: basic** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import { Paperclip, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; export component Basic() { {'File Upload'} {' Choose file(s)'} component children({ context }) { for (const file of @context.acceptedFiles; key file.name) { } } } ``` ### Initial Files Use the `defaultAcceptedFiles` prop to set the initial files in the file upload component. **Example: initial-files** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import { File as FileIcon, Paperclip, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; export component InitialFiles() { {'File Upload'} {' Choose file(s)'} component children({ context }) { for (const file of @context.acceptedFiles; key file.name) {
} }
} ``` ### Clear Trigger Use the `ClearTrigger` to remove all uploaded files at once. **Example: clear-trigger** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import { Paperclip, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; export component ClearTrigger() { {'File Upload'}
{' Choose file(s)'} {'Clear Files'}
component children({ context }) { for (const file of @context.acceptedFiles; key file.name) { } }
} ``` ### Dropzone Use the `Dropzone` to enable drag-and-drop. It exposes a `data-dragging` attribute for styling. **Example: dropzone** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import { File, Upload, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; export component Dropzone() { {'File Upload'}
{'Drag and drop files here'} {'or click to browse'}
component children({ context }) { for (const file of @context.acceptedFiles; key file.name) { } }
} ``` ### Directory Upload Use the `directory` prop to upload entire folders. Access file paths through `file.webkitRelativePath`. **Example: directory-upload** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import { File, Folder, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; export component DirectoryUpload() { {'Upload Folder'} {' Select Folder'} component children({ context }) { for (const file of @context.acceptedFiles; key file.name) {
{file.webkitRelativePath || file.name}
} }
} ``` > When uploading directories with many files, set `maxFiles` to a higher value or remove it entirely to prevent > rejections. ### Accepted File Types Use the `accept` prop to restrict file types. Accepts MIME types (`image/png`) or extensions (`.pdf`). **Example: accepted-file-types** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import { CircleAlert, Image, Upload, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; export component AcceptedFileTypes() { {'Upload Images (PNG and JPEG only)'}
{'Drop your images here'} {'Only PNG and JPEG files'}
component children({ context }) { if (@context.acceptedFiles.length > 0) { for (const file of @context.acceptedFiles; key file.name) { } } if (@context.rejectedFiles.length > 0) { for (const fileRejection of @context.rejectedFiles; key fileRejection.file.name) {
for (const error of fileRejection.errors; key error) {
{error}
}
}
} }
} ``` ### Error Handling Set constraints with `maxFiles`, `maxFileSize`, `minFileSize`, and `accept`. Rejected files include error codes like `TOO_MANY_FILES`, `FILE_INVALID_TYPE`, `FILE_TOO_LARGE`, or `FILE_EXISTS`. **Example: error-handling** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import type { FileUploadFileError } from 'ark-ripple/file-upload'; import { CircleAlert, CircleCheck, File, Upload, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; const errorMessages: Record = { TOO_MANY_FILES: 'Too many files selected (max 3 allowed)', FILE_INVALID_TYPE: 'Invalid file type (only images and PDFs allowed)', FILE_TOO_LARGE: 'File too large (max 1MB)', FILE_TOO_SMALL: 'File too small (min 1KB)', FILE_INVALID: 'Invalid file', FILE_EXISTS: 'File already exists', }; export component ErrorHandling() { {'Upload Documents'}
{'Drop files here'} {'Images and PDFs, max 1MB each'}
component children({ context }) { if (@context.acceptedFiles.length > 0) {
{'Accepted Files'}
for (const file of @context.acceptedFiles; key file.name) { }
} if (@context.rejectedFiles.length > 0) {
{'Rejected Files'}
for (const fileRejection of @context.rejectedFiles; key fileRejection.file.name) {
for (const error of fileRejection.errors; key error) {
{errorMessages[error as FileUploadFileError] || error}
}
}
} }
} ``` ### File Transformations Use `transformFiles` to process files before they're added. Useful for image compression, format conversion, or resizing. **Example: transform-files** ```ripple import { FileUpload } from 'ark-ripple/file-upload'; import { compressAccurately } from 'image-conversion'; import { Image, X } from 'lucide-ripple'; import styles from 'styles/file-upload.module.css'; const transformFiles = async (files: File[]) => { return Promise.all( files.map(async (file) => { if (file.type.startsWith('image/')) { try { const blob = await compressAccurately(file, 200); return new File([blob], file.name, { type: blob.type }); } catch (error) { console.error('Compression failed for:', file.name, error); return file; } } return file; }), ); }; export component TransformFiles() { {'Upload with Compression'} {' Choose Images'} component children({ context }) { for (const file of @context.acceptedFiles; key file.name) { } } } ``` ### Field Use `Field` to add helper text and error handling. **Example: with-field** ```ripple import { Field } from 'ark-ripple/field'; import { FileUpload } from 'ark-ripple/file-upload'; import { File, Upload, X } from 'lucide-ripple'; import field from 'styles/field.module.css'; import styles from 'styles/file-upload.module.css'; export component WithField() { {'Attachments'}
{'Drop files here'} {'or click to browse'}
component children({ context }) { for (const file of @context.acceptedFiles; key file.name) { } }
{'Upload up to 5 files'} {'Please upload at least one file'}
} ``` ### Root Provider An alternative way to control the file upload is to use the `RootProvider` component and the `useFileUpload` hook. This way you can access the state and methods from outside the component. **Example: root-provider** ```ripple import { FileUpload, useFileUpload } from 'ark-ripple/file-upload'; import { File, Upload, X } from 'lucide-ripple'; import button from 'styles/button.module.css'; import styles from 'styles/file-upload.module.css'; export component RootProvider() { const fileUpload = useFileUpload({ maxFiles: 5 });
{'File Upload'}
{'Drop files here'} {'or click to browse'}
component children({ context }) { for (const file of @context.acceptedFiles; key file.name) { } }
} ``` ### Pasting Files Use `setClipboardFiles` to enable pasting images from the clipboard. **Example: pasting-files** ```ripple import { FileUpload, useFileUpload } from 'ark-ripple/file-upload'; import { Clipboard, X } from 'lucide-ripple'; import field from 'styles/field.module.css'; import styles from 'styles/file-upload.module.css'; export component PastingFiles() { const fileUpload = useFileUpload({ maxFiles: 3, accept: 'image/*' }); {'Upload with Paste'}