# Upload Field (/docs/components/upload-field)



<ComponentPreview name="form-upload" />

## Installation [#installation]

<Tabs items="[&#x22;Command&#x22;, &#x22;Manual&#x22;]">
  <Tab value="Command">
    <CodeBlockTabs defaultValue="npm">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="npm">
          npm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="pnpm">
          pnpm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="yarn">
          yarn
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="bun">
          bun
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="npm">
        ```bash
        npx shadcn@latest add @uploadcn/upload-field
        ```
      </CodeBlockTab>

      <CodeBlockTab value="pnpm">
        ```bash
        pnpm dlx shadcn@latest add @uploadcn/upload-field
        ```
      </CodeBlockTab>

      <CodeBlockTab value="yarn">
        ```bash
        yarn dlx shadcn@latest add @uploadcn/upload-field
        ```
      </CodeBlockTab>

      <CodeBlockTab value="bun">
        ```bash
        bun x shadcn@latest add @uploadcn/upload-field
        ```
      </CodeBlockTab>
    </CodeBlockTabs>
  </Tab>

  <Tab value="Manual">
    Install [Upload](/docs/components/upload) first, then copy:

    <ComponentSource name="upload-field" />
  </Tab>
</Tabs>

## Usage [#usage]

```tsx
import { UploadField } from "@/components/upload-field"
```

```tsx
<Controller
  name="attachments"
  control={form.control}
  render={({ field, fieldState }) => (
    <UploadField
      label="Attachments"
      required
      maxFiles={3}
      error={fieldState.error?.message}
      onChange={field.onChange}
      onBlur={field.onBlur}
      onUploadingChange={setIsUploading}
    />
  )}
/>
```

The value is a list of object keys, not files: uploads happen while the user fills in the form, so submitting is instant.

## Props [#props]

<TypeTable
  type="{
  adapter: {
    type: &#x22;UploadAdapter&#x22;,
    default: 's3Adapter({ endpoint: &#x22;/api/upload&#x22; })',
    description: &#x22;Where files go.&#x22;,
  },
  label: { type: &#x22;ReactNode&#x22; },
  description: { type: &#x22;ReactNode&#x22; },
  error: {
    type: &#x22;string&#x22;,
    description:
      &#x22;Error message from your form library. Sets `data-invalid` and `aria-invalid`.&#x22;,
  },
  onChange: {
    type: &#x22;(value: string[]) => void&#x22;,
    description: &#x22;Values of successful uploads (object keys by default).&#x22;,
  },
  onBlur: { type: &#x22;() => void&#x22; },
  onUploadingChange: {
    type: &#x22;(uploading: boolean) => void&#x22;,
    description: &#x22;Block submission while files are uploading.&#x22;,
  },
  getValue: {
    type: &#x22;(item) => string&#x22;,
    description: &#x22;Value per successful upload.&#x22;,
  },
  required: { type: &#x22;boolean&#x22; },
  name: {
    type: &#x22;string&#x22;,
    description: &#x22;Also submits hidden inputs in native forms.&#x22;,
  },
  accept: { type: &#x22;string | string[]&#x22; },
  maxSize: { type: &#x22;number&#x22; },
  maxFiles: { type: &#x22;number&#x22; },
}"
/>

## Examples [#examples]

### Required upload (native form) [#required-upload-native-form]

<ComponentPreview name="required-upload" />

### File restrictions [#file-restrictions]

<ComponentPreview name="file-restrictions" />
