Files
Complete UI system for file uploading and management.
Overview
A complete file management system for browsing, selecting, and uploading files.
Use Files for the full compound UI, or Files.Provider plus lower-level pieces when you need a custom layout.
Key Concepts
Raw Rows In, UI Out
Pass your raw FileAsset rows. Files maps them to UI labels, icons, badges, and status display.
Upload Progress Overlay
Pass UploadProgressState (or UploadProgressLike) from your upload state. Active progress entries (0-100) override row status until complete.
Composable Components
Files: full compound file managerFiles.Provider: headless state provider for custom layoutsFileDetails: composable details panelFileListView,FileGridView: browse primitives
Data Contract
FileAsset
FileAsset is a discriminator union keyed by asset_type.
type FileAsset = StandardFileAsset | VirtualFileAsset;
type FileAssetBase = {
id: string;
name: string;
status: "active" | "archived" | "waiting" | "pending" | "failed";
created_at: Date | string | null;
updated_at: Date | string | null;
created_by: string | null;
created_by_image_url?: string | null;
indicators?: FileIndicator[];
icon?: React.ReactNode;
};
type StandardFileAsset = FileAssetBase & {
asset_type: "standard";
mime_type: string;
size: number | bigint | string | null;
};
type VirtualFileAsset = FileAssetBase & {
asset_type: "virtual";
virtual_type: string;
};What this means for consumers:
asset_type: "standard"requiresmime_typeandsize.asset_type: "virtual"requiresvirtual_type.- Do not mix standard and virtual-only fields on the same row.
FileIndicator
type FileIndicator = {
label: string;
icon: React.ReactNode;
};Indicators render as compact badges on list/grid items (up to 2).
Upload Progress
type UploadProgressState = {
percentage: number; // 0-100
filesCompleted: number;
totalFiles: number;
fileProgress: Map<
string,
{
id: string;
percentage: number; // 0-100
status: "waiting" | "pending" | "uploading" | "completed" | "failed";
etaSeconds?: number;
}
>;
};Virtual Files
Use virtual rows for derived content (for example transcripts or summaries) that does not map to a real uploaded blob.
import { Scroll } from "@tilt-legal/cubitt-icons/ui/outline";
const transcript: FileAsset = {
id: "virtual-1",
name: "Meeting Notes Transcript",
asset_type: "virtual",
virtual_type: "transcript",
status: "active",
created_by: "System",
created_at: "2025-01-10T09:00:00.000Z",
updated_at: "2025-01-10T09:00:00.000Z",
icon: <Scroll />,
};Virtual files often shouldn't be renameable. Use the canRename predicate on Files to disable rename for specific files:
<Files
files={files}
onRename={handleRename}
canRename={(file) => !file.isVirtual}
>