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-partattribute 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
RootProvidercomponent, you don't need to use theRootcomponent.