Ark UI Logo
Components
File upload

File Upload

A component that is used to upload multiple files.

Loading...

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>
  )
}

Validation

Use the validate prop to validate the files before they are uploaded. The return value of the function should map to:

  • TOO_MANY_FILES: If the user tries to upload more files than the maxFiles prop allows.
  • FILE_INVALID_TYPE: If the file is of an invalid type.
  • FILE_TOO_LARGE: If the file is too large.
  • FILE_TOO_SMALL: If the file is too small.
  • FILE_INVALID: If the file is invalid (for any other reason).
  • FILE_EXISTS: If the file already exists.
import { FileUpload } from '@ark-ui/react/file-upload'
import { FileIcon } from 'lucide-react'

export const WithValidation = () => {
  return (
    <FileUpload.Root
      validate={(file) => {
        if (file.name.length > 20) return ['FILE_NAME_TOO_LONG']
        return null
      }}
    >
      <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>
  )
}

Field

Here's an example of how to use the FileUpload component with the Field component to provide a error and helper text.

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>
)

Root Provider

Use the useFileUpload hook to create the file upload store and pass it to the FileUpload.RootProvider component. This allows you to have maximum control over the file upload programmatically.

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>
    </>
  )
}

If you're using the RootProvider component, you don't need to use the Root component.

API Reference

Root

PropDefaultType
accept
Record<string, string[]> | FileMimeType | FileMimeType[]

The accept file types

acceptedFiles
File[]

The controlled accepted files

allowDroptrue
boolean

Whether to allow drag and drop in the dropzone element

asChild
boolean

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

defaultAcceptedFiles
File[]

The default accepted files when rendered. Use when you don't need to control the accepted files of the input.

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.

maxFiles1
number

The maximum number of files

maxFileSizeInfinity
number

The maximum file size in bytes

minFileSize0
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

preventDocumentDroptrue
boolean

Whether to prevent the drop event on the document

required
boolean

Whether the file input is required

transformFiles
(files: File[]) => Promise<File[]>

Function to transform the accepted files to apply transformations

translations
IntlTranslations

The localized messages to use.

validate
(file: File, details: FileValidateDetails) => FileError[] | null

Function to validate a file

Data AttributeValue
[data-scope]file-upload
[data-part]root
[data-disabled]Present when disabled
[data-dragging]Present when in the dragging state

ClearTrigger

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]clear-trigger
[data-disabled]Present when disabled

Dropzone

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
disableClick
boolean

Whether to disable the click event on the dropzone

Data AttributeValue
[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

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

ItemDeleteTrigger

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]item-delete-trigger
[data-disabled]Present when disabled

ItemGroup

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]item-group
[data-disabled]Present when disabled

ItemName

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]item-name
[data-disabled]Present when disabled

ItemPreviewImage

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]item-preview-image
[data-disabled]Present when disabled

ItemPreview

PropDefaultType
asChild
boolean

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 AttributeValue
[data-scope]file-upload
[data-part]item-preview
[data-disabled]Present when disabled

Item

PropDefaultType
file
File

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]item
[data-disabled]Present when disabled

ItemSizeText

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]item-size-text
[data-disabled]Present when disabled

Label

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]label
[data-disabled]Present when disabled

RootProvider

PropDefaultType
value
UseFileUploadReturn

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Trigger

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]file-upload
[data-part]trigger
[data-disabled]Present when disabled
[data-invalid]Present when invalid

Design System Support

Expert design system support from the creators of Ark UI

Get Support