File Upload
A component that is used to upload multiple files.
Anatomy
To set up the file upload component correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-part
attribute to help identify them in the DOM.
Examples
Learn how to use the FileUpload
component in your project. Let's take a look at the most basic
example:
import { FileUpload } from '@ark-ui/react/file-upload'
import { FileIcon } from 'lucide-react'
export const Basic = () => {
return (
<FileUpload.Root maxFiles={5}>
<FileUpload.Label>File Upload</FileUpload.Label>
<FileUpload.Dropzone>Drag your file(s) here</FileUpload.Dropzone>
<FileUpload.Trigger>Choose file(s)</FileUpload.Trigger>
<FileUpload.ItemGroup>
<FileUpload.Context>
{({ acceptedFiles }) =>
acceptedFiles.map((file) => (
<FileUpload.Item key={file.name} file={file}>
<FileUpload.ItemPreview type="image/*">
<FileUpload.ItemPreviewImage />
</FileUpload.ItemPreview>
<FileUpload.ItemPreview type=".*">
<FileIcon />
</FileUpload.ItemPreview>
<FileUpload.ItemName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger>X</FileUpload.ItemDeleteTrigger>
</FileUpload.Item>
))
}
</FileUpload.Context>
</FileUpload.ItemGroup>
<FileUpload.HiddenInput />
</FileUpload.Root>
)
}
import { FileUpload } from '@ark-ui/solid/file-upload'
import { For } from 'solid-js'
export const Basic = () => (
<FileUpload.Root maxFiles={5}>
<FileUpload.Label>File Upload</FileUpload.Label>
<FileUpload.Dropzone>Drag your file(s) here</FileUpload.Dropzone>
<FileUpload.Trigger>Choose file(s)</FileUpload.Trigger>
<FileUpload.ItemGroup>
<FileUpload.Context>
{(context) => (
<For each={context().acceptedFiles}>
{(file) => (
<FileUpload.Item file={file}>
<FileUpload.ItemPreview type="image/*">
<FileUpload.ItemPreviewImage />
</FileUpload.ItemPreview>
<FileUpload.ItemPreview type=".*">Any Icon</FileUpload.ItemPreview>
<FileUpload.ItemName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger>X</FileUpload.ItemDeleteTrigger>
</FileUpload.Item>
)}
</For>
)}
</FileUpload.Context>
</FileUpload.ItemGroup>
<FileUpload.HiddenInput />
</FileUpload.Root>
)
<script setup lang="ts">
import { FileUpload } from '@ark-ui/vue/file-upload'
</script>
<template>
<FileUpload.Root :maxFiles="5">
<FileUpload.Label>File Upload</FileUpload.Label>
<FileUpload.Dropzone>Drop your files here</FileUpload.Dropzone>
<FileUpload.Trigger>Choose file(s)</FileUpload.Trigger>
<FileUpload.ItemGroup>
<FileUpload.Context v-slot="{ acceptedFiles }">
<FileUpload.Item v-for="file in acceptedFiles" :file="file" :key="file.name">
<FileUpload.ItemPreview type="image/*">
<FileUpload.ItemPreviewImage />
</FileUpload.ItemPreview>
<FileUpload.ItemPreview type=".*">
<div>Generic Icon</div>
</FileUpload.ItemPreview>
<FileUpload.ItemName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger>X</FileUpload.ItemDeleteTrigger>
</FileUpload.Item>
</FileUpload.Context>
</FileUpload.ItemGroup>
<FileUpload.HiddenInput />
</FileUpload.Root>
</template>
Using the Field Component
The Field
component helps manage form-related state and accessibility attributes of an file upload.
It includes handling ARIA labels, helper text, and error text to ensure proper accessibility.
import { Field } from '@ark-ui/react/field'
import { FileUpload } from '@ark-ui/react/file-upload'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props}>
<FileUpload.Root maxFiles={5}>
<FileUpload.Label>Label</FileUpload.Label>
<FileUpload.Trigger>Select</FileUpload.Trigger>
<FileUpload.ItemGroup />
<FileUpload.HiddenInput data-testid="input" />
</FileUpload.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
import { Field } from '@ark-ui/solid/field'
import { FileUpload } from '@ark-ui/solid/file-upload'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props}>
<FileUpload.Root maxFiles={5}>
<FileUpload.Label>Label</FileUpload.Label>
<FileUpload.Trigger>Select</FileUpload.Trigger>
<FileUpload.ItemGroup />
<FileUpload.HiddenInput data-testid="input" />
</FileUpload.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
<script setup lang="ts">
import { Field } from '@ark-ui/vue/field'
import { FileUpload } from '@ark-ui/vue/file-upload'
</script>
<template>
<Field.Root>
<FileUpload.Root :maxFiles="5">
<FileUpload.Label>Label</FileUpload.Label>
<FileUpload.Trigger>Select</FileUpload.Trigger>
<FileUpload.ItemGroup />
<FileUpload.HiddenInput data-testid="input" />
</FileUpload.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
</template>
Using the Root Provider
The RootProvider
component provides a context for the file-upload. It accepts the value of the useFile-upload
hook.
You can leverage it to access the component state and methods from outside the file-upload.
import { FileUpload, useFileUpload } from '@ark-ui/react/file-upload'
import { FileIcon } from 'lucide-react'
export const RootProvider = () => {
const fileUpload = useFileUpload({ maxFiles: 5 })
return (
<>
<button onClick={() => fileUpload.clearFiles()}>Clear</button>
<FileUpload.RootProvider value={fileUpload}>
<FileUpload.Label>File Upload</FileUpload.Label>
<FileUpload.Dropzone>Drag your file(s) here</FileUpload.Dropzone>
<FileUpload.Trigger>Choose file(s)</FileUpload.Trigger>
<FileUpload.ItemGroup>
<FileUpload.Context>
{({ acceptedFiles }) =>
acceptedFiles.map((file) => (
<FileUpload.Item key={file.name} file={file}>
<FileUpload.ItemPreview type="image/*">
<FileUpload.ItemPreviewImage />
</FileUpload.ItemPreview>
<FileUpload.ItemPreview type=".*">
<FileIcon />
</FileUpload.ItemPreview>
<FileUpload.ItemName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger>X</FileUpload.ItemDeleteTrigger>
</FileUpload.Item>
))
}
</FileUpload.Context>
</FileUpload.ItemGroup>
<FileUpload.HiddenInput />
</FileUpload.RootProvider>
</>
)
}
import { FileUpload, useFileUpload } from '@ark-ui/solid/file-upload'
import { For } from 'solid-js'
export const RootProvider = () => {
const fileUpload = useFileUpload({ maxFiles: 5 })
return (
<>
<button onClick={() => fileUpload().clearFiles()}>Clear</button>
<FileUpload.RootProvider value={fileUpload}>
<FileUpload.Label>File Upload</FileUpload.Label>
<FileUpload.Dropzone>Drag your file(s)here</FileUpload.Dropzone>
<FileUpload.Trigger>Choose file(s)</FileUpload.Trigger>
<FileUpload.ItemGroup>
<FileUpload.Context>
{(context) => (
<For each={context().acceptedFiles}>
{(file) => (
<FileUpload.Item file={file}>
<FileUpload.ItemPreview type="image/*">
<FileUpload.ItemPreviewImage />
</FileUpload.ItemPreview>
<FileUpload.ItemPreview type=".*">Any Icon</FileUpload.ItemPreview>
<FileUpload.ItemName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger>X</FileUpload.ItemDeleteTrigger>
</FileUpload.Item>
)}
</For>
)}
</FileUpload.Context>
</FileUpload.ItemGroup>
<FileUpload.HiddenInput />
</FileUpload.RootProvider>
</>
)
}
<script setup lang="ts">
import { FileUpload, useFileUpload } from '@ark-ui/vue/file-upload'
const fileUpload = useFileUpload({ maxFiles: 5 })
</script>
<template>
<button @click="fileUpload.clearFiles()">Clear</button>
<FileUpload.RootProvider :value="fileUpload">
<FileUpload.Label>File Upload</FileUpload.Label>
<FileUpload.Dropzone>Drop your files here</FileUpload.Dropzone>
<FileUpload.Trigger>Choose file(s)</FileUpload.Trigger>
<FileUpload.ItemGroup>
<FileUpload.Context v-slot="{ acceptedFiles }">
<FileUpload.Item v-for="file in acceptedFiles" :file="file" :key="file.name">
<FileUpload.ItemPreview type="image/*">
<FileUpload.ItemPreviewImage />
</FileUpload.ItemPreview>
<FileUpload.ItemPreview type=".*">
<div>Generic Icon</div>
</FileUpload.ItemPreview>
<FileUpload.ItemName />
<FileUpload.ItemSizeText />
<FileUpload.ItemDeleteTrigger>X</FileUpload.ItemDeleteTrigger>
</FileUpload.Item>
</FileUpload.Context>
</FileUpload.ItemGroup>
<FileUpload.HiddenInput />
</FileUpload.RootProvider>
</template>
If you're using the
RootProvider
component, you don't need to use theRoot
component.
API Reference
Root
Prop | Default | Type |
---|---|---|
accept | Record<string, string[]> | FileMimeType | FileMimeType[] The accept file types | |
allowDrop | true | boolean Whether to allow drag and drop in the dropzone element |
asChild | (props: ParentProps<'div'>) => Element Use 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 | boolean Whether to accept directories, only works in webkit browsers | |
disabled | boolean Whether 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 | boolean Whether the file input is invalid | |
locale | 'en-US' | string The current locale. Based on the BCP 47 definition. |
maxFiles | 1 | number The maximum number of files |
maxFileSize | Infinity | number The maximum file size in bytes |
minFileSize | 0 | number The minimum file size in bytes |
name | string The name of the underlying file input | |
onFileAccept | (details: FileAcceptDetails) => void Function called when the file is accepted | |
onFileChange | (details: FileChangeDetails) => void Function called when the value changes, whether accepted or rejected | |
onFileReject | (details: FileRejectDetails) => void Function called when the file is rejected | |
required | boolean Whether the file input is required | |
translations | IntlTranslations The localized messages to use. | |
validate | (file: File, details: FileValidateDetails) => FileError[] | null Function to validate a file |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | root |
[data-disabled] | Present when disabled |
[data-dragging] | Present when in the dragging state |
ClearTrigger
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'button'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | clear-trigger |
[data-disabled] | Present when disabled |
Dropzone
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'div'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | dropzone |
[data-invalid] | Present when invalid |
[data-disabled] | Present when disabled |
[data-dragging] | Present when in the dragging state |
HiddenInput
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'input'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
ItemDeleteTrigger
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'button'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | item-delete-trigger |
[data-disabled] | Present when disabled |
ItemGroup
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'ul'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | item-group |
[data-disabled] | Present when disabled |
ItemName
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'div'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | item-name |
[data-disabled] | Present when disabled |
ItemPreviewImage
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'img'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | item-preview-image |
[data-disabled] | Present when disabled |
ItemPreview
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'div'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
type | '.*' | string The file type to match against. Matches all file types by default. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | item-preview |
[data-disabled] | Present when disabled |
Item
Prop | Default | Type |
---|---|---|
file | File | |
asChild | (props: ParentProps<'li'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | item |
[data-disabled] | Present when disabled |
ItemSizeText
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'div'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | item-size-text |
[data-disabled] | Present when disabled |
Label
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'label'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | label |
[data-disabled] | Present when disabled |
RootProvider
Prop | Default | Type |
---|---|---|
value | UseFileUploadReturn | |
asChild | (props: ParentProps<'div'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Trigger
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'button'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | file-upload |
[data-part] | trigger |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |