Upload Paste

Wrap any upload component or block, animated ones too, and it takes screenshots and files pasted with Ctrl+V or Cmd+V.

"use client"

import { PolaroidUpload } from "@/components/polaroid-upload"
import { UploadPaste } from "@/components/upload-paste"

export default function UploadPasteExample() {
  return (
    <UploadPaste hint>
      <PolaroidUpload maxFiles={6} />
    </UploadPaste>
  )
}

Hover over the polaroids (or tab to the dropzone) and paste a screenshot. The block inside was not changed: UploadPaste turns paste on for whatever it wraps.

Installation

npx shadcn@latest add @uploadcn/upload-paste

Usage

import { UploadPaste } from "@/components/upload-paste"
<UploadPaste>
  <FolderUpload />
</UploadPaste>

That is the whole setup. It works with every UploadCN component and block, because they are all built on <Upload>: the wrapper tells the uploads inside it to take pasted files, and each one handles them like dropped files, with its own accept, maxSize and maxFiles. The test suite wraps every block in the registry, pastes a file into it and checks the block takes it the way it takes a picked file.

Some blocks do more than queue a file, and a pasted file goes the same way:

BlockWhat a pasted file does
Folder Upload, Polaroid, Rocket and the other animated blocksJoins the animation like a dropped file
Image Upload, Avatar UploadOpens the crop step first, when cropping is on
CSV Import, OCR Upload, Receipt UploadIs parsed or read like a picked file
Identity Verification, Document Checklist, Job ApplicationFills the slot you are on, or the first empty slot
Upload Dialog, Upload PopoverIs taken while the dialog or popover is open
Global UploadIs taken anywhere inside the provider
Chat AttachmentsAlready takes pastes in its composer, with or without the wrapper

Where a paste goes

A paste is taken while the component is focused or the pointer is over it. Pastes into text inputs, textareas and contenteditable elements are never touched, and neither are pastes that carry only text.

{/* Anywhere on the page: for one uploader per page */}
<UploadPaste global>
  <FileUpload />
</UploadPaste>

{/* Several uploaders: each takes the paste while it is the one in use */}
<UploadPaste>
  <AvatarUpload />
  <GalleryUpload />
</UploadPaste>

Accessibility

  • Paste is a keyboard path: tab to the dropzone and press Ctrl+V or ⌘+V. Nothing needs a pointer.
  • The dropzone exposes the shortcut with aria-keyshortcuts, and the hint reads as “Command V” to screen readers instead of the ⌘ symbol.
  • A polite live region announces the files that were added, and each rejected file with its reason.
  • Focus does not move when you paste, and text fields are never intercepted, so pasting text keeps working everywhere.

Hint

hint shows the shortcut under the component, so people know they can paste. Pass your own text to change or translate it, or place UploadPasteHint yourself.

<UploadPaste hint>
  <VinylUpload />
</UploadPaste>

<UploadPaste hint="Strg+V fügt einen Screenshot ein">
  <VinylUpload />
</UploadPaste>

Other ways to turn paste on

UploadPaste is for components whose <Upload> you can't reach. When you can, use the prop, and to turn paste on everywhere, use the provider:

{/* A component you compose yourself, and the File Upload block */}
<Upload paste>…</Upload>
<FileUpload paste />

{/* Every upload component in your app */}
<UploadConfigProvider adapter={adapter} paste>
  {children}
</UploadConfigProvider>

See Paste for how pasted files are named and validated.

Props

Prop

Type

On this page

Sponsor UploadCNPut your logo in front of developers choosing how their app uploads files.