Loading state
Wait for asynchronous initial files before rendering UI or enabling actions.
Declarative gating
Render a skeleton while initial files are loading, then render your preview once hydration is complete.
import {UplofileRoot,UplofileTrigger,UplofilePreview,} from "@/components/ui/uplofile";import { mockUpload } from "@/lib/utils.ts";export default function LoadingStateDeclarativeDemo() {return (<UplofileRootupload={mockUpload}initial={loadInitial()}accept="image/*"multiple><UplofileTriggerasChildrender={({ isLoading, open }) => (<buttononClick={open}disabled={isLoading}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">{isLoading ? "Loading initial files…" : "Select Images"}</button>)}/><div className="mt-6"><UplofilePreviewrender={({ isLoading, items }) => {if (isLoading) {return (<div className="grid grid-cols-3 gap-3">{Array.from({ length: 3 }).map((_, i) => (<divkey={i}className="aspect-square rounded-lg bg-muted animate-pulse"/>))}</div>);}return (<div className="grid grid-cols-3 gap-3">{items.map((item) => (<imgkey={item.uid}src={item.url || item.previewUrl}alt={item.name}className="aspect-square w-full h-full object-cover rounded-lg border"/>))}</div>);}}/></div></UplofileRoot>);}// Simulate async initial files hydration from serverconst loadInitial = () =>new Promise<Array<{ uid: string; name: string; url: string }>>((resolve) => {setTimeout(() =>resolve([{uid: "srv-1",name: "server-image.jpg",url: "https://picsum.photos/id/237/600/400",},]),3500,);});
Imperative subscription
Subscribe to loading changes using an imperative ref, and toggle your own UI state when hydration completes.
Hydrating initial files…
import { useEffect, useRef, useState } from "react";import type { UplofileRootRef } from "uplofile";import {UplofileRoot,UplofilePreview,UplofileTrigger,} from "@/components/ui/uplofile";import { mockUpload } from "@/lib/utils.ts";import { twMerge } from "tailwind-merge";export default function LoadingStateImperativeDemo() {const rootRef = useRef<UplofileRootRef>(null);const [ready, setReady] = useState(false);useEffect(() => {// Subscribe imperatively to hydration statusif (!rootRef.current) return;rootRef.current.onLoadingChange = (loading) => {setReady(!loading);};}, []);return (<div className="space-y-4"><div className="flex items-center gap-2 text-sm"><divclassName={`h-2 w-2 rounded-full ${ready ? "bg-emerald-500" : "bg-amber-500 animate-pulse"}`}/><span>{ready ? "Hydrated • ready" : "Hydrating initial files…"}</span></div><UplofileRootref={rootRef}upload={mockUpload}initial={loadInitial()}accept="image/*"><UplofileTriggerrender={({ open }) => (<buttononClick={open}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 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 shadow">Add more</button>)}/><div className={"grid mt-6 gap-3 items-center grid-cols-3"}><UplofilePreview className="!block" />{Array.from({ length: 3 }).map((_, i) => (<divkey={i}className={twMerge("aspect-square rounded-lg bg-muted animate-pulse",ready && "hidden",)}/>))}</div></UplofileRoot></div>);}const loadInitial = () =>new Promise<Array<{ uid: string; name: string; url: string }>>((resolve) => {setTimeout(() =>resolve([{uid: "srv-2",name: "hydrated-from-server.jpg",url: "https://picsum.photos/id/1025/600/400",},]),6000,);});
Form integration
Prevent premature form submission by disabling the submit button until initial files finish hydrating.
import {UplofileRoot,UplofileHiddenInput,UplofilePreview,UplofileTrigger,} from "@/components/ui/uplofile";import { mockUpload } from "@/lib/utils.ts";import { IoSendOutline, IoReloadOutline } from "react-icons/io5";export default function LoadingStateFormDemo() {const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {e.preventDefault();const fd = new FormData(e.currentTarget);alert("Submitted! Check console for payload.");console.log(Object.fromEntries(fd));};return (<form className="space-y-4" onSubmit={handleSubmit}><UplofileRootupload={mockUpload}initial={loadInitial()}name="attachments"><UplofileHiddenInput /><UplofileTriggerrender={({ isLoading, open }) => (<buttontype="button"onClick={open}disabled={isLoading}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">{isLoading ? (<span className="inline-flex items-center gap-2"><IoReloadOutline className="h-4 w-4 animate-spin" />{" "}Preparing…</span>) : ("Add attachments")}</button>)}/><UplofilePreviewrender={({ items, isLoading }) => (<div className="mt-4 space-y-2">{isLoading && (<p className="text-xs text-muted-foreground">Hydrating initial attachments…</p>)}{items.map((it) => (<div key={it.uid} className="text-sm text-muted-foreground">• {it.name}</div>))}</div>)}/><div className="pt-2 border-t mt-4"><UplofileTriggerrender={({ isLoading }) => (<buttontype="submit"disabled={isLoading}className="w-full inline-flex items-center justify-center gap-2 rounded-lg text-sm font-bold ring-offset-background transition-all 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-gray-900 text-white hover:bg-gray-800 h-11 px-8 shadow-lg"><IoSendOutline className="h-4 w-4" />{isLoading ? "Please wait…" : "Submit"}</button>)}/></div></UplofileRoot></form>);}const loadInitial = () =>new Promise<Array<{ uid: string; name: string; url: string }>>((resolve) => {setTimeout(() =>resolve([{uid: "srv-3",name: "doc-from-server.pdf",url: "https://example.com/doc-from-server.pdf",},]),6000,);});