File Manager
blockmediaStorage/files page with breadcrumbs, search, grid/list view toggle, upload action, and a storage meter over hardcoded folders and files.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/react/file-manager.json$npx shadcn@latest add https://uipkge.dev/r/react/file-manager.json$yarn dlx shadcn@latest add https://uipkge.dev/r/react/file-manager.json$bunx shadcn@latest add https://uipkge.dev/r/react/file-manager.jsonNamed registry:
npx shadcn@latest add @uipkge-react/file-managerInstalls to:components/blocks/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
variant | 'grid' | 'list' | — | optional |
className | string | — | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
FolderIteminterface FolderItem {
id: string
name: string
count: number
}FileIteminterface FileItem {
id: string
name: string
kind: FileKind
size: string
modified: string
}npm dependencies
Files installed (1)
components/blocks/FileManager.tsx10.7 kB
'use client' import { useState } from 'react' import { Download, FileArchive, FileImage, FileSpreadsheet, FileText, FileVideo, Folder, LayoutGrid, List, MoreVertical, Pencil, Search, Share2, Trash2, Upload, } from 'lucide-react' import { cn } from '@/lib/utils' import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, } from '@/components/ui/breadcrumb' import { Button } from '@/components/ui/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { Input } from '@/components/ui/input' import { Progress } from '@/components/ui/progress' import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group' type FileKind = 'pdf' | 'image' | 'sheet' | 'video' | 'archive' interface FolderItem { id: string name: string count: number } interface FileItem { id: string name: string kind: FileKind size: string modified: string } export interface FileManagerProps { variant?: 'grid' | 'list' className?: string } const folders: FolderItem[] = [ { id: 'folder-design-assets', name: 'Design Assets', count: 24 }, { id: 'folder-client-files', name: 'Client Files', count: 12 }, { id: 'folder-brand-kit', name: 'Brand Kit', count: 8 }, { id: 'folder-archive', name: 'Archive', count: 56 }, ] const files: FileItem[] = [ { id: 'file-brand-guidelines', name: 'brand-guidelines.pdf', kind: 'pdf', size: '4.2 MB', modified: 'Mar 14, 2026' }, { id: 'file-homepage-hero', name: 'homepage-hero.png', kind: 'image', size: '2.8 MB', modified: 'Mar 12, 2026' }, { id: 'file-logo-final', name: 'logo-final.svg', kind: 'image', size: '48 KB', modified: 'Mar 10, 2026' }, { id: 'file-pricing-model', name: 'pricing-model.xlsx', kind: 'sheet', size: '316 KB', modified: 'Mar 8, 2026' }, { id: 'file-launch-video', name: 'launch-video.mp4', kind: 'video', size: '184 MB', modified: 'Mar 5, 2026' }, { id: 'file-app-iconset', name: 'app-iconset.zip', kind: 'archive', size: '12.4 MB', modified: 'Feb 27, 2026' }, ] const fileKindIcons: Record<FileKind, typeof FileText> = { pdf: FileText, image: FileImage, sheet: FileSpreadsheet, video: FileVideo, archive: FileArchive, } export function FileManager({ variant = 'grid', className }: FileManagerProps) { const [view, setView] = useState<'grid' | 'list'>(variant) const rows = [...folders.map((f) => ({ ...f, isFolder: true })), ...files.map((f) => ({ ...f, isFolder: false }))] return ( <div data-slot="file-manager" className={cn('w-full', className)}> <div className="bg-card text-card-foreground rounded-xl border shadow-xs"> <div className="flex flex-wrap items-center gap-3 border-b p-4"> <Breadcrumb> <BreadcrumbList> <BreadcrumbItem> <BreadcrumbLink href="#" className="inline-flex min-h-6 items-center"> Home </BreadcrumbLink> </BreadcrumbItem> <BreadcrumbSeparator /> <BreadcrumbItem> <BreadcrumbLink href="#" className="inline-flex min-h-6 items-center"> Documents </BreadcrumbLink> </BreadcrumbItem> <BreadcrumbSeparator /> <BreadcrumbItem> <BreadcrumbPage>Design</BreadcrumbPage> </BreadcrumbItem> </BreadcrumbList> </Breadcrumb> <div className="relative ml-auto w-full max-w-56 sm:w-auto"> <Search aria-hidden="true" className="text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2" /> <Input type="search" placeholder="Search files…" className="pl-8" /> </div> <ToggleGroup type="single" size="sm" value={view} className="bg-muted items-center gap-0.5 rounded-md p-0.5" aria-label="View mode" onValueChange={(v) => v && setView(v as 'grid' | 'list')} > <ToggleGroupItem value="grid" className="data-[state=on]:bg-background size-7 rounded-sm p-0 data-[state=on]:shadow-sm" title="Grid view" aria-label="Grid view" > <LayoutGrid aria-hidden="true" className="size-4" /> </ToggleGroupItem> <ToggleGroupItem value="list" className="data-[state=on]:bg-background size-7 rounded-sm p-0 data-[state=on]:shadow-sm" title="List view" aria-label="List view" > <List aria-hidden="true" className="size-4" /> </ToggleGroupItem> </ToggleGroup> <Button size="sm"> <Upload aria-hidden="true" className="size-4" /> Upload </Button> </div> <div className="flex flex-wrap items-center gap-x-4 gap-y-2 border-b px-4 py-3"> <Progress value={36.4} className="h-1.5 min-w-40 flex-1 sm:max-w-xs" aria-label="Storage used" /> <p className="text-muted-foreground text-xs">18.2 GB of 50 GB used</p> </div> {view === 'grid' ? ( <div className="grid grid-cols-2 gap-3 p-4 sm:grid-cols-3 lg:grid-cols-4"> {folders.map((folder) => ( <button key={folder.id} type="button" className="hover:bg-muted/50 focus-visible:ring-ring flex flex-col items-start gap-3 rounded-lg border p-3 text-left shadow-xs transition-colors focus-visible:ring-2 focus-visible:outline-none" > <span className="bg-warning/10 text-warning grid size-9 place-items-center rounded-md"> <Folder className="size-5" /> </span> <span className="min-w-0"> <span className="block truncate text-sm font-medium">{folder.name}</span> <span className="text-muted-foreground block text-xs">{folder.count} items</span> </span> </button> ))} {files.map((file) => { const Icon = fileKindIcons[file.kind] return ( <button key={file.id} type="button" className="hover:bg-muted/50 focus-visible:ring-ring group flex flex-col items-start gap-3 rounded-lg border p-3 text-left shadow-xs transition-colors focus-visible:ring-2 focus-visible:outline-none" > <span className="bg-muted text-muted-foreground group-hover:bg-background grid size-9 place-items-center rounded-md transition-colors"> <Icon className="size-5" /> </span> <span className="w-full min-w-0"> <span className="block truncate text-sm font-medium">{file.name}</span> <span className="text-muted-foreground block text-xs"> {file.size} · {file.modified} </span> </span> </button> ) })} </div> ) : ( <div role="table" aria-label="Files and folders"> <div role="row" className="text-muted-foreground hidden border-b px-4 py-2 text-xs sm:flex"> <span role="columnheader" className="flex-1 pl-9"> Name </span> <span role="columnheader" className="w-20 text-right"> Size </span> <span role="columnheader" className="w-28 text-right"> Modified </span> <span className="w-9" /> </div> <ul role="rowgroup" className="divide-y"> {rows.map((item) => { const Icon = item.isFolder ? Folder : fileKindIcons[(item as FileItem).kind] return ( <li key={item.id} role="row" className="hover:bg-muted/50 flex items-center gap-3 px-4 py-2.5 transition-colors" > <span className={cn( 'grid size-6 shrink-0 place-items-center rounded-md', item.isFolder ? 'bg-warning/10 text-warning' : 'bg-muted text-muted-foreground', )} > <Icon className="size-4" /> </span> <span role="cell" className="min-w-0 flex-1 truncate text-sm font-medium"> {item.name} </span> <span role="cell" className="text-muted-foreground hidden w-20 shrink-0 text-right text-xs sm:block" > {item.isFolder ? `${(item as FolderItem).count} items` : (item as FileItem).size} </span> <span role="cell" className="text-muted-foreground hidden w-28 shrink-0 text-right text-xs md:block" > {item.isFolder ? '—' : (item as FileItem).modified} </span> <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" size="icon-sm" className="shrink-0" aria-label={`Actions for ${item.name}`} > <MoreVertical className="size-4" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end"> <DropdownMenuItem> <Download className="size-4" /> Download </DropdownMenuItem> <DropdownMenuItem> <Pencil className="size-4" /> Rename </DropdownMenuItem> <DropdownMenuItem> <Share2 className="size-4" /> Share link </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem variant="destructive"> <Trash2 className="size-4" /> Delete </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </li> ) })} </ul> </div> )} </div> </div> ) }
Raw manifest:https://uipkge.dev/r/react/file-manager.json