Introduction

Production-ready file uploads, built for shadcn.

UploadCN is a set of upload primitives, hooks and complete upload experiences for shadcn/ui. It solves the part of file uploads that a dropzone doesn't: queues, concurrency, retries, chunked and resumable transfers, presigned S3/R2 flows, validation, image processing, server-side processing and scan states, offline recovery, persistence and accessibility.

"use client"

import { FileUpload } from "@/components/file-upload"

export default function BasicUploadExample() {
  return <FileUpload maxSize={50 * 1000 * 1000} />
}

How it's distributed

UploadCN follows the same split as shadcn's own components:

LayerWhat it isHow you get it
UI componentsStyled, composable shadcn components and blocksnpx shadcn add @uploadcn/…, copied into your project
@uploadcn/reactHooks and headless, accessible primitivesnpm dependency, installed by the CLI
@uploadcn/coreThe framework-agnostic upload engine and adaptersnpm dependency, installed by the CLI
@uploadcn/serverA Web-standard upload route for S3, R2 and friendsnpm dependency of the route item

You own every class name and every line of markup. The parts that are easy to get subtly wrong, retry policies, multipart bookkeeping, request signing, live in small, tested packages you upgrade like any dependency, the same way shadcn's Drawer builds on vaul and its Toast on sonner.

What's in the box

Principles

  • Composable. Use the parts you need; replace the rest. Every primitive supports a render prop.
  • Honest. No fake progress, no client-side "virus scanning", no background uploads the browser can't deliver.
  • Accessible. Keyboard-operable dropzones, real progressbars and a polite live region announcing results.
  • Storage-agnostic. The UI doesn't care where bytes go. Adapters are plain objects.
  • Framework-agnostic core. Next.js, TanStack Start, Vite, React Router, the engine has no React or Next.js dependency.

On this page