Uploader
Drop-and-paste upload widget with progress, retry, and a multi-file queue.
<AuraUploader /> is a Shadcn-registry component you copy into your project. It handles drag-and-drop, click-to-browse, paste-from-clipboard, a multi-file queue with per-row progress, cancel/retry, and drag-reorder of queued files.
Uploads go directly to cdn.auraimage.ai — your backend only mints the signature, never handles the bytes.
Install
npx shadcn@latest add https://auraimage.ai/registry/uploader.jsonThis copies src/components/aura/uploader.tsx and pulls in its lucide-react and shadcn cn() deps. It reads your CDN base URL from NEXT_PUBLIC_AURA_CDN_URL.
Usage
import { AuraUploader } from '@/components/aura/uploader';
export default function ProfilePage() {
return (
<AuraUploader
project='my-app'
onUpload={(result) => {
console.log(result.url); // final CDN URL
console.log(result.key); // store this for setVisibility / getSignedUrl
console.log(result.blurhash); // store for placeholder rendering
}}
maxSize='5mb'
multiple
/>
);
}Signature delivery
The component supports three ways to obtain a signature, resolved in this precedence order:
getSignature— async function. Highest precedence. Use for custom auth flows, signature caching, or refresh logic.signature— pre-computed string. Useful from a Server Component that mints the signature at render time.project— project name. The component POSTs{ project, filename, contentType, size }to/api/aura/signon your own backend and expects{ signature }back.
You only need one. The most common pattern is project="my-app" + a small route handler:
import { AuraImage } from '@auraimage/sdk';
const aura = new AuraImage({
secretKey: process.env.AURA_SECRET_KEY!,
projectName: process.env.NEXT_PUBLIC_AURA_PROJECT_NAME!
});
export async function POST() {
const signature = await aura.signUpload({
maxSize: '5mb',
allowedTypes: ['image/*'],
expiresIn: 3600
});
return Response.json({ signature });
}For RSC-minted signatures:
import { AuraUploader } from '@/components/aura/uploader';
import { aura } from '@/lib/aura';
export default async function Page() {
const signature = await aura.signUpload({ maxSize: '5mb' });
return <AuraUploader signature={signature} />;
}For custom auth (Firebase, Clerk, …):
<AuraUploader
getSignature={async () => {
const token = await getFirebaseIdToken();
const res = await fetch('/api/sign', { headers: { Authorization: `Bearer ${token}` } });
return (await res.json()).signature;
}}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
onUpload | (result: UploadResult) => void | — | Called once per successful file. |
onError | (error: Error) => void | — | Called on validation failure (size cap) or upload failure. |
maxSize | string | "5mb" | Client-side size cap. The edge enforces its own limit from the signature — keep them in sync. |
accept | string | "image/*" | MIME filter for the file picker. |
multiple | boolean | false | Allow multiple files. When false, dropping a new file replaces the queue. |
concurrency | number | 3 | Max simultaneous uploads. |
className | string | — | Extra classes merged onto the dropzone container. |
getSignature | () => Promise<string> | string | — | Async signature provider (highest precedence). |
signature | string | — | Pre-computed signature. |
project | string | — | Project name. Triggers the /api/aura/sign convention. |
UploadResult shape (matches the upload response):
interface UploadResult {
url: string;
key: string;
blurhash: string;
width: number;
height: number;
format: string;
size: number;
}Behavior
- Drag-and-drop with an outlined active state on the whole container.
- Click to browse — the container is keyboard-focusable (
Enter/Spaceopens the picker). - Paste-from-clipboard — while the uploader has focus, pasted images are queued automatically.
- Per-row UI — thumbnail, filename, byte size, 2 px progress bar, status, and per-row remove / cancel / retry.
- Drag-reorder of queued (not-yet-uploaded) items.
- Concurrency — uploads run in parallel up to
concurrency(default3). - Copy-URL pill on each successful row.
All thumbnails use object URLs that are revoked on unmount or removal — no leaks.
Live demo
The landing page runs a real <AuraUploader> against production. Drop an image into the Edge proxy upload tile on auraimage.ai to see the full flow.