File Upload
Used to select and upload files from their device.
import { Button, FileUpload } from "@chakra-ui/react"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUpload.Root>
<FileUpload.HiddenInput />
<FileUpload.Trigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUpload.Trigger>
<FileUpload.List />
</FileUpload.Root>
)
}
Usage
import { FileUpload } from "@chakra-ui/react"<FileUpload.Root>
<FileUpload.HiddenInput />
<FileUpload.Label />
<FileUpload.Dropzone>
<FileUpload.DropzoneContent />
</FileUpload.Dropzone>
<FileUpload.Trigger />
<FileUpload.ItemGroup>
<FileUpload.Item>
<FileUpload.ItemPreview />
<FileUpload.ItemFileName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger />
</FileUpload.Item>
</FileUpload.ItemGroup>
</FileUpload.Root>Shortcuts
The FileUpload component also provides a set of shortcuts for common use
cases.
FileUploadItems
By default, the FileUploadItems shortcut renders the list of uploaded files.
This works:
<FileUpload.ItemGroup>
<FileUpload.Context>
{({ acceptedFiles }) =>
acceptedFiles.map((file) => (
<FileUpload.Item key={file.name} file={file}>
<FileUpload.ItemPreview />
<FileUpload.ItemName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger />
</FileUpload.Item>
))
}
</FileUpload.Context>
</FileUpload.ItemGroup>This might be more concise, if you don't need to customize the file upload items:
<FileUpload.ItemGroup>
<FileUpload.Items />
</FileUpload.ItemGroup>FileUploadList
The FileUploadList shortcut renders the list of uploaded files. It composes
the FileUpload.ItemGroup and FileUpload.Items components.
<FileUpload.List />is the same as:
<FileUpload.ItemGroup>
<FileUpload.Items />
</FileUpload.ItemGroup>Examples
Accepted Files
Define the accepted files for upload using the accept prop.
import { Button, FileUpload } from "@chakra-ui/react"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUpload.Root accept={["image/png"]}>
<FileUpload.HiddenInput />
<FileUpload.Trigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUpload.Trigger>
<FileUpload.List />
</FileUpload.Root>
)
}
Multiple Files
Upload multiple files at once by using the maxFiles prop.
import { Button, FileUpload } from "@chakra-ui/react"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUpload.Root maxFiles={5}>
<FileUpload.HiddenInput />
<FileUpload.Trigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUpload.Trigger>
<FileUpload.List showSize clearable />
</FileUpload.Root>
)
}
Custom Preview
Here's an example of how to show a custom image preview for files.
"use client"
import {
Button,
FileUpload,
Float,
useFileUploadContext,
} from "@chakra-ui/react"
import { LuFileImage, LuX } from "react-icons/lu"
const FileUploadList = () => {
const fileUpload = useFileUploadContext()
const files = fileUpload.acceptedFiles
if (files.length === 0) return null
return (
<FileUpload.ItemGroup>
{files.map((file) => (
<FileUpload.Item
w="auto"
boxSize="20"
p="2"
file={file}
key={file.name}
>
<FileUpload.ItemPreviewImage />
<Float placement="top-end">
<FileUpload.ItemDeleteTrigger boxSize="4" layerStyle="fill.solid">
<LuX />
</FileUpload.ItemDeleteTrigger>
</Float>
</FileUpload.Item>
))}
</FileUpload.ItemGroup>
)
}
const Demo = () => {
return (
<FileUpload.Root accept="image/*">
<FileUpload.HiddenInput />
<FileUpload.Trigger asChild>
<Button variant="outline" size="sm">
<LuFileImage /> Upload Images
</Button>
</FileUpload.Trigger>
<FileUploadList />
</FileUpload.Root>
)
}
Directory
Use the directory prop to allow selecting a directory instead of a file.
import { Button, FileUpload } from "@chakra-ui/react"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUpload.Root directory>
<FileUpload.HiddenInput />
<FileUpload.Trigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUpload.Trigger>
<FileUpload.List />
</FileUpload.Root>
)
}
Media Capture
Use the capture prop to select and upload files from different environments
and media types.
Note: This is not fully supported in all browsers.
import { Button, FileUpload } from "@chakra-ui/react"
import { HiCamera } from "react-icons/hi"
const Demo = () => {
return (
<FileUpload.Root capture="environment">
<FileUpload.HiddenInput />
<FileUpload.Trigger asChild>
<Button variant="outline" size="sm">
<HiCamera /> Open Camera
</Button>
</FileUpload.Trigger>
<FileUpload.List />
</FileUpload.Root>
)
}
Dropzone
Drop multiple files inside the dropzone and use the maxFiles prop to set the
number of files that can be uploaded at once.
import { Box, FileUpload, Icon } from "@chakra-ui/react"
import { LuUpload } from "react-icons/lu"
const Demo = () => {
return (
<FileUpload.Root maxW="xl" alignItems="stretch" maxFiles={10}>
<FileUpload.HiddenInput />
<FileUpload.Dropzone>
<Icon size="md" color="fg.muted">
<LuUpload />
</Icon>
<FileUpload.DropzoneContent>
<Box>Drag and drop files here</Box>
<Box color="fg.muted">.png, .jpg up to 5MB</Box>
</FileUpload.DropzoneContent>
</FileUpload.Dropzone>
<FileUpload.List />
</FileUpload.Root>
)
}
Conditional Dropzone
Hide the dropzone when the maximum number of files has been reached by using
useFileUploadContext to access the accepted files count.
"use client"
import { Box, FileUpload, Icon, useFileUploadContext } from "@chakra-ui/react"
import { LuUpload } from "react-icons/lu"
const MAX_FILES = 3
const ConditionalDropzone = () => {
const fileUpload = useFileUploadContext()
const acceptedFiles = fileUpload.acceptedFiles
if (acceptedFiles.length >= MAX_FILES) {
return null
}
return (
<FileUpload.Dropzone>
<Icon size="md" color="fg.muted">
<LuUpload />
</Icon>
<FileUpload.DropzoneContent>
<Box>Drag and drop files here</Box>
<Box color="fg.muted">
{MAX_FILES - acceptedFiles.length} more file
{MAX_FILES - acceptedFiles.length !== 1 ? "s" : ""} allowed
</Box>
</FileUpload.DropzoneContent>
</FileUpload.Dropzone>
)
}
const Demo = () => {
return (
<FileUpload.Root maxW="xl" alignItems="stretch" maxFiles={MAX_FILES}>
<FileUpload.HiddenInput />
<ConditionalDropzone />
<FileUpload.List clearable />
</FileUpload.Root>
)
}
Input
Use the FileInput component to create a trigger that looks like a text input.
import { FileUpload, Input } from "@chakra-ui/react"
const Demo = () => {
return (
<FileUpload.Root gap="1" maxWidth="300px">
<FileUpload.HiddenInput />
<FileUpload.Label>Upload file</FileUpload.Label>
<Input asChild>
<FileUpload.Trigger>
<FileUpload.FileText />
</FileUpload.Trigger>
</Input>
</FileUpload.Root>
)
}
Clearable
Here's an example of a clearable file upload input.
import { CloseButton, FileUpload, Input, InputGroup } from "@chakra-ui/react"
import { LuFileUp } from "react-icons/lu"
const Demo = () => {
return (
<FileUpload.Root gap="1" maxWidth="300px">
<FileUpload.HiddenInput />
<FileUpload.Label>Upload file</FileUpload.Label>
<InputGroup
startElement={<LuFileUp />}
endElement={
<FileUpload.ClearTrigger asChild>
<CloseButton
me="-1"
size="xs"
variant="plain"
focusVisibleRing="inside"
focusRingWidth="2px"
pointerEvents="auto"
/>
</FileUpload.ClearTrigger>
}
>
<Input asChild>
<FileUpload.Trigger>
<FileUpload.FileText lineClamp={1} />
</FileUpload.Trigger>
</Input>
</InputGroup>
</FileUpload.Root>
)
}
Pasting Files
Here's an example of handling files pasted from the clipboard.
"use client"
import {
FileUpload,
Float,
HStack,
Input,
type InputProps,
useFileUploadContext,
} from "@chakra-ui/react"
import { HiX } from "react-icons/hi"
const FilePasteInput = (props: InputProps) => {
const fileUpload = useFileUploadContext()
return (
<Input
{...props}
onPaste={(e) => {
fileUpload.setClipboardFiles(e.clipboardData)
}}
/>
)
}
const FileImageList = () => {
const fileUpload = useFileUploadContext()
return (
<HStack wrap="wrap" gap="3">
{fileUpload.acceptedFiles.map((file) => (
<FileUpload.Item
p="2"
width="auto"
key={file.name}
file={file}
pos="relative"
>
<Float placement="top-start">
<FileUpload.ItemDeleteTrigger
p="0.5"
rounded="l1"
bg="bg"
borderWidth="1px"
>
<HiX />
</FileUpload.ItemDeleteTrigger>
</Float>
<FileUpload.ItemPreviewImage
boxSize="12"
rounded="l1"
objectFit="cover"
/>
</FileUpload.Item>
))}
</HStack>
)
}
const Demo = () => {
return (
<FileUpload.Root maxFiles={3} accept="image/*">
<FileUpload.HiddenInput />
<FileImageList />
<FilePasteInput placeholder="Paste image here..." />
</FileUpload.Root>
)
}
Store
An alternative way to control the file upload is to use the RootProvider
component and the useFileUpload store hook.
This way you can access the file upload state and methods from outside the file upload.
accepted: rejected: "use client"
import {
Button,
Code,
FileUpload,
Stack,
useFileUpload,
} from "@chakra-ui/react"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
const fileUpload = useFileUpload({
maxFiles: 1,
maxFileSize: 3000,
})
const accepted = fileUpload.acceptedFiles.map((file) => file.name)
const rejected = fileUpload.rejectedFiles.map((e) => e.file.name)
return (
<Stack align="flex-start">
<Code colorPalette="green">accepted: {accepted.join(", ")}</Code>
<Code colorPalette="red">rejected: {rejected.join(", ")}</Code>
<FileUpload.RootProvider value={fileUpload}>
<FileUpload.HiddenInput />
<FileUpload.Trigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUpload.Trigger>
<FileUpload.List />
</FileUpload.RootProvider>
</Stack>
)
}
Props
Root
| Prop | Default | Type |
|---|---|---|
allowDrop | true | booleanWhether to allow drag and drop in the dropzone element |
locale | '\'en-US\'' | stringThe current locale. Based on the BCP 47 definition. |
maxFiles | '1' | numberThe maximum number of files |
maxFileSize | 'Infinity' | numberThe maximum file size in bytes |
minFileSize | '0' | numberThe minimum file size in bytes |
preventDocumentDrop | true | booleanWhether to prevent the drop event on the document |
as | React.ElementTypeThe underlying element to render. | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | booleanWhether to remove the component's style. | |
accept | Record<string, string[]> | FileMimeType | FileMimeType[]The accept file types | |
acceptedFiles | File[]The controlled accepted files | |
capture | 'user' | 'environment'The default camera to use when capturing media | |
defaultAcceptedFiles | File[]The default accepted files when rendered. Use when you don't need to control the accepted files of the input. | |
directory | booleanWhether to accept directories, only works in webkit browsers | |
disabled | booleanWhether the file input is disabled | |
ids | Partial<{
root: string
dropzone: string
hiddenInput: string
trigger: string
label: string
item: (id: string) => string
itemName: (id: string) => string
itemSizeText: (id: string) => string
itemPreview: (id: string) => string
}>The ids of the elements. Useful for composition. | |
invalid | booleanWhether the file input is invalid | |
name | stringThe name of the underlying file input | |
onFileAccept | (details: FileAcceptDetails) => voidFunction called when the file is accepted | |
onFileChange | (details: FileChangeDetails) => voidFunction called when the value changes, whether accepted or rejected | |
onFileReject | (details: FileRejectDetails) => voidFunction called when the file is rejected | |
required | booleanWhether the file input is required | |
transformFiles | (files: File[]) => Promise<File[]>Function to transform the accepted files to apply transformations | |
translations | IntlTranslationsThe localized messages to use. | |
validate | (file: File, details: FileValidateDetails) => FileError[] | nullFunction to validate a file |
Explorer
Explore the File Upload component parts interactively. Click on parts in the
sidebar to highlight them in the preview.
Let’s Add Some Naruto Images
You can upload up to 6 images by dragging them here or browsing.
Drag & drop files here
or click below to browse files
Select file(s)Uploaded Files
- uzumaki_naruto.svg266 byte
Component Anatomy
Hover to highlight, click to select parts
root
dropzone
item
itemDeleteTrigger
itemGroup
itemName
itemPreview
itemPreviewImage
itemSizeText
label
trigger
clearTrigger
itemContent
dropzoneContent
fileText
file-upload.recipe.ts