import { Button } from "@chakra-ui/react"
import {
FileUploadList,
FileUploadRoot,
FileUploadTrigger,
} from "@/components/ui/file-upload"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUploadRoot>
<FileUploadTrigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUploadTrigger>
<FileUploadList />
</FileUploadRoot>
)
}
Setup
If you don't already have the snippet, run the following command to add the
file-upload snippet
npx @chakra-ui/cli snippet add file-upload
The snippet includes a closed component composition for the FileUpload
component.
Usage
import {
FileUploadList,
FileUploadRoot,
FileUploadTrigger,
} from "@/components/ui/file-upload"
<FileUploadRoot>
<FileUploadTrigger>
<Button>
<HiUpload /> Upload file
</Button>
</FileUploadTrigger>
<FileUploadList />
</FileUploadRoot>
Examples
Directory
Use the directory prop to allow selecting a directory instead of a file.
import { Button } from "@chakra-ui/react"
import {
FileUploadList,
FileUploadRoot,
FileUploadTrigger,
} from "@/components/ui/file-upload"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUploadRoot directory>
<FileUploadTrigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUploadTrigger>
<FileUploadList />
</FileUploadRoot>
)
}
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 } from "@chakra-ui/react"
import {
FileUploadList,
FileUploadRoot,
FileUploadTrigger,
} from "@/components/ui/file-upload"
import { HiCamera } from "react-icons/hi"
const Demo = () => {
return (
<FileUploadRoot capture="environment">
<FileUploadTrigger asChild>
<Button variant="outline" size="sm">
<HiCamera /> Open Camera
</Button>
</FileUploadTrigger>
<FileUploadList />
</FileUploadRoot>
)
}
Multiple Files
Upload multiple files at once by using the maxFiles prop.
import { Button } from "@chakra-ui/react"
import {
FileUploadList,
FileUploadRoot,
FileUploadTrigger,
} from "@/components/ui/file-upload"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUploadRoot maxFiles={5}>
<FileUploadTrigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUploadTrigger>
<FileUploadList showSize clearable />
</FileUploadRoot>
)
}
Dropzone
Drop multiple files inside the dropzone and use the maxFiles prop to set the
number of files that can be uploaded at once.
.png, .jpg up to 5MB
import {
FileUploadDropzone,
FileUploadList,
FileUploadRoot,
} from "@/components/ui/file-upload"
const Demo = () => {
return (
<FileUploadRoot maxW="xl" alignItems="stretch" maxFiles={10}>
<FileUploadDropzone
label="Drag and drop here to upload"
description=".png, .jpg up to 5MB"
/>
<FileUploadList />
</FileUploadRoot>
)
}
Input
Use the FileInput component to create a trigger that looks like a text input.
import {
FileInput,
FileUploadLabel,
FileUploadRoot,
} from "@/components/ui/file-upload"
const Demo = () => {
return (
<FileUploadRoot gap="1" maxWidth="300px">
<FileUploadLabel>Upload file</FileUploadLabel>
<FileInput />
</FileUploadRoot>
)
}
Clearable
Here's an example of a clearable file upload input.
import { CloseButton } from "@/components/ui/close-button"
import {
FileInput,
FileUploadClearTrigger,
FileUploadLabel,
FileUploadRoot,
} from "@/components/ui/file-upload"
import { InputGroup } from "@/components/ui/input-group"
import { LuFileUp } from "react-icons/lu"
const Demo = () => {
return (
<FileUploadRoot gap="1" maxWidth="300px">
<FileUploadLabel>Upload file</FileUploadLabel>
<InputGroup
w="full"
startElement={<LuFileUp />}
endElement={
<FileUploadClearTrigger asChild>
<CloseButton
me="-1"
size="xs"
variant="plain"
focusVisibleRing="inside"
focusRingWidth="2px"
pointerEvents="auto"
color="fg.subtle"
/>
</FileUploadClearTrigger>
}
>
<FileInput />
</InputGroup>
</FileUploadRoot>
)
}
Accepted Files
Define the accepted files for upload using the accept prop.
import { Button } from "@chakra-ui/react"
import {
FileUploadList,
FileUploadRoot,
FileUploadTrigger,
} from "@/components/ui/file-upload"
import { HiUpload } from "react-icons/hi"
const Demo = () => {
return (
<FileUploadRoot accept={["image/png"]}>
<FileUploadTrigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUploadTrigger>
<FileUploadList />
</FileUploadRoot>
)
}
Pasting Files
Here's an example of handling files pasted from the clipboard.
"use client"
import {
FileUpload,
FileUploadItemPreviewImage,
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>
<FileUploadItemPreviewImage
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,
FileUploadHiddenInput,
FileUploadRootProvider,
Stack,
useFileUpload,
} from "@chakra-ui/react"
import { FileUploadList, FileUploadTrigger } from "@/components/ui/file-upload"
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>
<FileUploadRootProvider value={fileUpload}>
<FileUploadHiddenInput />
<FileUploadTrigger asChild>
<Button variant="outline" size="sm">
<HiUpload /> Upload file
</Button>
</FileUploadTrigger>
<FileUploadList />
</FileUploadRootProvider>
</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 |
accept | Record<string, string[]> | FileMimeType | FileMimeType[]The accept file types | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
capture | 'user' | 'environment'The default camera to use when capturing media | |
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 | |
translations | IntlTranslationsThe localized messages to use. | |
validate | (file: File, details: FileValidateDetails) => FileError[] | nullFunction to validate a file | |
as | React.ElementTypeThe underlying element to render. | |
unstyled | booleanWhether to remove the component's style. |