Uplofile is open sourceStar on GitHub

Default & Custom Preview

Compare the built-in preview with a custom render tailored to a compact file list.

Default Preview

Default Preview:

1import {
2 UplofileRoot,
3 UplofileTrigger,
4 UplofilePreview,
5} from "@/components/ui/uplofile";
6import { mockUpload } from "@/lib/utils.ts";
7
8export default function DefaultPreviewStyledDemo() {
9 return (
10 <UplofileRoot
11 upload={mockUpload}
12 initial={[
13 {
14 uid: "v1",
15 name: "v1.mp4",
16 url: "https://www.w3schools.com/html/mov_bbb.mp4",
17 },
18 ]}
19 >
20 <UplofileTrigger asChild>
21 <button className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 shadow">
22 Select Files
23 </button>
24 </UplofileTrigger>
25
26 <div className="mt-8 border-t pt-8">
27 <h3 className="text-sm font-medium mb-4">Default Preview:</h3>
28 <UplofilePreview />
29 </div>
30 </UplofileRoot>
31 );
32}

Custom Preview

Custom Preview:

    1import {
    2 UplofileRoot,
    3 UplofileTrigger,
    4 UplofilePreview,
    5} from "@/components/ui/uplofile";
    6import { mockOnRemove, mockUpload } from "@/lib/utils.ts";
    7
    8export default function DefaultPreviewCustomDemo() {
    9 return (
    10 <UplofileRoot
    11 upload={mockUpload}
    12 onRemove={mockOnRemove}
    13 removeMode="strict"
    14 >
    15 <UplofileTrigger asChild>
    16 <button className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 shadow">
    17 Select Files
    18 </button>
    19 </UplofileTrigger>
    20
    21 <div className="mt-8 border-t pt-8">
    22 <h3 className="text-sm font-medium mb-4">Custom Preview:</h3>
    23 <UplofilePreview
    24 render={({ items, actions }) => (
    25 <ul className="space-y-2">
    26 {items.map((item) => (
    27 <li
    28 key={item.uid}
    29 className="flex items-center gap-3 rounded-lg border border-border bg-background p-3 text-sm shadow-sm transition-opacity data-[removing=true]:opacity-70"
    30 data-removing={item.status === "removing"}
    31 >
    32 <div className="min-w-0 flex-1">
    33 <div className="flex items-center gap-2">
    34 <span className="truncate font-medium text-foreground">
    35 {item.name}
    36 </span>
    37 <span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-xs font-medium capitalize text-muted-foreground">
    38 {item.status === "removing" ? "removing" : item.status}
    39 </span>
    40 </div>
    41 {item.status === "uploading" && (
    42 <div className="mt-2 h-1.5 overflow-hidden rounded-full bg-muted">
    43 <div
    44 className="h-full rounded-full bg-primary transition-[width]"
    45 style={{ width: `${item.progress ?? 0}%` }}
    46 />
    47 </div>
    48 )}
    49 </div>
    50 <button
    51 type="button"
    52 onClick={() => {
    53 if (item.status === "uploading") {
    54 actions.cancel(item.uid);
    55 return;
    56 }
    57 actions.remove(item.uid);
    58 }}
    59 disabled={item.status === "removing"}
    60 className="inline-flex h-8 shrink-0 items-center justify-center gap-2 rounded-md border border-border px-3 text-xs font-medium text-destructive transition-colors hover:bg-destructive hover:text-destructive-foreground disabled:pointer-events-none disabled:text-muted-foreground"
    61 aria-label={`${
    62 item.status === "uploading" ? "Cancel upload for" : "Remove"
    63 } ${item.name} (${item.uid})`}
    64 >
    65 {item.status === "removing" && (
    66 <span
    67 className="h-3.5 w-3.5 animate-spin rounded-full border-2 border-current border-t-transparent"
    68 aria-hidden="true"
    69 />
    70 )}
    71 {item.status === "removing"
    72 ? "Removing"
    73 : item.status === "uploading"
    74 ? "Cancel"
    75 : "Remove"}
    76 </button>
    77 </li>
    78 ))}
    79 </ul>
    80 )}
    81 />
    82 </div>
    83 </UplofileRoot>
    84 );
    85}

    Key Points

    • Built-in UplofilePreview with polished default styling
    • Grid layout with aspect-ratio squares and hover overlays
    • Integrated progress bars, retry, and cancel actions
    • Custom render prop for intent-built preview rows