Drop overlay
FreeLets a whole area take dropped files: a clear target rises over the content while files are dragged in and names what will happen.
pnpm dlx shadcn@latest add https://caliperui.site/r/drop-overlay.jsonDocuments
- board-pack-q3.pdf
- contract-ostra.docx
Or drag files anywhere onto this panel.
When to use #
Use it for
- Document lists, chats and media libraries.
- Anywhere a file button already exists.
Skip it when
- The only way to upload; dragging is not available to everyone.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/drop-overlay.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
import { useState } from "react" import { DropOverlay } from "@/components/ui/drop-overlay" export function DropOverlayDemo() { const [files, setFiles] = useState<string[]>([]); return ( <DropOverlay className="w-full max-w-md rounded-[14px]" onFiles={(added) => setFiles((current) => [...added.map((file) => file.name), ...current])} hint="PDF or images, up to 20 MB each" accept={["image/", ".pdf"]}> <div className="grid gap-3 rounded-[14px] p-5 shadow-[inset_0_0_0_1px_var(--border)]"> <div className="flex items-center justify-between gap-3"> <p className="text-sm font-medium">Documents</p> <label className="cursor-pointer rounded-[9px] px-3 py-1.5 text-sm font-medium shadow-[inset_0_0_0_1px_var(--border)] focus-within:outline-2 focus-within:outline-ring"> Choose files <input type="file" multiple className="sr-only" onChange={(event) => setFiles((current) => [...Array.from(event.target.files ?? []).map((file) => file.name), ...current])} /> </label> </div> <ul className="grid gap-1 text-sm text-muted-foreground"> {(files.length ? files : ["board-pack-q3.pdf", "contract-ostra.docx"]).map((name) => <li key={name}>{name}</li>)} </ul> <p className="text-xs text-muted-foreground">Or drag files anywhere onto this panel.</p> </div> </DropOverlay> ); }
API reference #
DropOverlay
component
Accessibility #
It exposes status semantics, with aria-hidden kept in step with state. Changes that matter are announced through a live region.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.