Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Data Display

File List

Data Display

File List React component for Tailwind CSS v4

Diff ViewerFile manager
Live props
Layout
layout
Appearance
size
variant
radius
tone
color
showThumbnails
Content
showMeta
timeFormat
locale
Behavior
actionsVisibility
confirmDelete
selectionMode
State
loading
skeletonCount3
Code
import { FileList } from "@/components/ui/file-list"

<FileList />
  1. Home
  2. Components
  3. Data Display
  4. File List
Pro

File List React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React file list for attachments and documents: rows, preview tiles or chips with type icons, thumbnails, upload progress and file actions.

Click or tap a file to preview it (photos open in place in the demo, documents open their url in a new tab by default); the row tints on hover and press. Photos fade in as they load, and a picture that fails falls back to its type tile. On desktop the download button sits at the end of each row and the ⋯ menu (shown on hover or focus, always on touch) holds the extra actions and Delete, which asks first in an alert dialog and fades the row while it runs; right click opens the same menu. When the list is narrower than 448px (a phone, a sidebar card) download moves into the ⋯ menu and uploaders show as a face only; on a phone the menu opens as a bottom sheet, and a long press opens it too. Uploading files show a thin progress bar with "64% · 2,4 of 3,8 MB" and a cancel ×; processing shows a moving bar; a failed upload shows its reason in red with Retry and remove; when an upload finishes its progress crossfades into the size and time with a quick check mark. With selectionMode="multiple" each file gets a checkbox: click it, Shift + click for a range, or long press on touch; while something is selected a click on a file toggles it. Keyboard: Tab reaches each file and its buttons, Up / Down (and Left / Right in the grid and chips) move between files, Home / End jump, Page Up / Page Down move by 10, Enter previews, Space toggles selection, Shift + Space or Shift + arrows extend it, Ctrl / Cmd + A selects all, Escape clears, Delete or Backspace deletes the focused file (with the confirm), Shift + F10 or the Menu key opens its menu (from the file or any of its buttons). Files enter and leave on a soft spring; reduced motion turns movement into fades.

File List is a Pro React component in the React data display components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add file-list, together with Alert Dialog, Avatar, Button, Checkbox, Dropdown Menu and 11 more and the npm packages lucide-react and motion.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add file-list

File List is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import FileList from @/components/ui/file-list.

import { useState } from "react"
import { FileList, type FileItem } from "@/components/ui/file-list"

const initial: FileItem[] = [
  { id: "f1", name: "Invoice 2026-0412.pdf", size: 253952, url: "/files/invoice-2026-0412.pdf", uploadedAt: "2026-09-22T11:20:00", uploadedBy: { name: "Olivia Bennett" } },
  { id: "f2", name: "Sales report Q3 2026.xlsx", size: 1258291, url: "/files/report-q3.xlsx", uploadedAt: "2026-09-24T10:12:00", uploadedBy: { name: "Liam Walker" } },
  { id: "f3", name: "Admin ID scan.pdf", size: 3984589, status: "uploading", progress: 0.64 },
]

export function ClientDocuments() {
  const [files, setFiles] = useState(initial)
  const remove = (file: FileItem) => setFiles((prev) => prev.filter((f) => f.id !== file.id))
  return (
    <FileList
      files={files}
      locale="en-US"
      onDelete={async (file) => {
        await fetch(`/api/files/${file.id}`, { method: "DELETE" })
        remove(file)
      }}
      onCancel={remove}
      getActions={(file) => [{ label: "Copy link", onSelect: () => navigator.clipboard.writeText(file.url ?? "") }]}
      labels={{ deleteTitle: (name) => `Delete “${name}” for everyone?` }}
    />
  )
}

Props

  • files
    FileItem[]

    { id, name, size?, type?, url?, thumbnailUrl?, previewUrl?, uploadedAt?, uploadedBy?: { name, avatar? }, status?: "done" | "uploading" | "processing" | "error" | "idle" | "canceled", progress? (0..1), error?, description?, disabled? }. FileUpload's UploadFile[] fits as it is. To render one file on its own, use FileListItem (see Parts). Unknown sizes are left out of the meta line; heic and tiff never try to render.

  • layoutdefault "list"
    "list" | "grid" | "compact"

    list: rows with a thumb, name, meta and actions. grid: preview tiles (4:3 photos or a big type tile) in auto-fill columns of at least 10rem, 2 columns on a phone. compact: 40px chips that wrap, for email attachments.

  • sizedefault "md"
    "sm" | "md"

    List rows 44 / 56px with 32 / 40px thumbs and a 13 / 14px name.

  • variantdefault "surface"
    "plain" | "surface" | "separated"

    surface: one raised panel with hairlines (raised tiles and chips in the other layouts); plain: rows with hairlines and no container (flat gray tiles, tinted chips); separated: a panel per file (outlined tiles and chips).

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg"

    Panel and tile corners: 0 / 12 / 16 / 24px; previews inside a tile follow at the radius minus the padding. Chips are pills from md up.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The selection checkbox, the selected ring on tiles and chips, and the upload progress fill.

  • colordefault ""
    string

    Any CSS color; replaces the tone. Leave empty to use the tone.

  • showThumbnailsdefault true
    boolean

    Photo previews for images (thumbnailUrl, then previewUrl, then url). Off shows the colored type tile for every file.

  • showMetadefault true
    boolean

    The size · time · uploader line under the name. Upload progress and errors show either way.

  • timeFormatdefault "relative"
    "relative" | "time" | "date" | "datetime"

    How uploadedAt reads: "2 days ago", "4:40 PM", "9/22/2026" or both. Relative text waits for the browser, so the server prints the date and time.

  • actionsVisibilitydefault "hover"
    "hover" | "always"

    The ⋯ button: shown on hover and focus (always on touch screens), or always.

  • confirmDeletedefault true
    boolean

    Delete asks first in an alert dialog. Off deletes right away (email attachments).

  • selectionModedefault "none"
    "none" | "multiple"

    multiple adds a checkbox per finished file, Shift ranges, Ctrl / Cmd + A and Escape, and long press to select on touch. Uploading and failed files cannot be selected.

  • loadingdefault false
    boolean

    Skeletons in the shape of the layout (rows, tiles or chips) instead of the files, with aria-busy.

  • skeletonCountdefault 3
    number

    How many skeletons show while loading.

  • localedefault ""
    string

    Sizes ("2.4 MB") and times ("2 days ago"). Empty uses the UIProvider locale, then the browser's. The demo falls back to en-US.

  • onPreview
    (file: FileItem, index: number) => void

    Clicking a file or pressing Enter on it. Without it a file with a url opens in a new tab.

  • onDownload
    (file: FileItem) => void

    The download action. Without it the download button is a link to the url with the download attribute.

  • onDelete
    (file: FileItem) => (void | Promise<unknown>)

    Shows Delete in the ⋯ menu (and the Delete key). A returned promise fades the row to 50% until it settles; afterwards focus moves to the next file. Also removes a failed upload (without asking).

  • onCancel
    (file: FileItem) => void

    The × on uploading, waiting and processing files; also removes a failed upload when there is no onDelete.

  • onRetry
    (file: FileItem) => void

    Retry on failed uploads.

  • getActions
    (file: FileItem) => MenuEntry[]

    Extra ⋯ entries in the W1 MenuEntry shape (Rename, Move, Copy link), above Delete. In compact chips it turns the trailing button into a ⋯.

  • selectedKeys
    string[]

    The selected file ids (controlled). Pair with onSelectedKeysChange.

  • defaultSelectedKeysdefault "[]"
    string[]

    The initial selection when uncontrolled.

  • onSelectedKeysChange
    (keys: string[]) => void

    Every selection change, in display order.

  • emptyState
    ReactNode

    Shown when files is empty. Defaults to <EmptyState size="sm" preset="empty" icon={<Paperclip />} /> with labels.empty.

  • labels
    Partial<FileListLabels>

    Every string, merged over DEFAULT_FILE_LIST_LABELS: preview, download, delete, cancel, retry, remove, actions and select ({name}), uploading ({ percent, loaded, total }) => string, processing, queued, canceled, failed, uploaded, deleteTitle (name) => string, deleteDescription, deleteConfirm, deleteCancel, sheetTitle, sheetCancel, empty, emptyDescription, loading, kinds (screen reader names per file kind).

  • classNames
    Partial<Record<"item" | "main" | "select" | "thumb" | "body" | "name" | "meta" | "description" | "progress" | "error" | "actions" | "empty" | "skeleton", string>>

    Extra classes for the inner parts.

  • className
    string

    Extra classes for the root (the panel, grid or chip row).

Parts

  • FileListItem

    component

    One file as a row, a tile or a chip, following the FileList around it; on its own it is a plain row that opens its url. Takes every div prop plus the ones below.

    • file*
      FileItem

      The file to render (see FileItem).

    • indexdefault 0
      number

      The position handed to onPreview.

  • DEFAULT_FILE_LIST_LABELS

    constant

    Every English string: the file actions (Preview, Download, Delete, Cancel upload, Retry, Remove), the "{name}" templates for the menu and selection, upload states ("42% · 1.2 MB of 3 MB"), the delete dialog, the action sheet and the empty and loading states. Spread it into labels to translate a few. Type: FileListLabels.

  • FileItem

    type

    One file: { id, name, size?, type?, url?, thumbnailUrl?, previewUrl?, uploadedAt?, uploadedBy?, status?, progress?, error?, description?, disabled? }. status is "done", "uploading", "processing", "error", "idle" or "canceled"; progress runs from 0 to 1.

Examples

Grid with photo previews

layout="grid": listing photos fill 4:3 tiles, documents show their kind tile; 2 columns on a phone.

Email attachments

layout="compact": wrapping chips under a composer, with a total and a remove button.

Selection with a bulk bar

selectionMode="multiple" with a select-all checkbox, Shift ranges and bulk actions.

Upload queue

FileUpload picks the files, FileList shows progress, cancel, a failure and retry.

Loading and empty

Skeletons in the row shape while loading, then the files or an EmptyState.

Narrow sidebar

size="sm" plain rows in a 300px card: 44px rows with 32px thumbs.

Separated, brand selection

A panel per file with a description line, brand checkboxes and the ⋯ always visible.

Dependencies

lucide-reactmotionalert-dialogavatarbuttoncheckboxdropdown-menuempty-statefile-typesmotionprogressrelative-timeskeletontonesui-configuse-localeuse-long-pressuse-selection

Files

  • components/ui/file-list.tsx

FAQ

Is the React File List component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install File List?

Run npx wingo-ui@latest add file-list. It also adds the Wingo UI items it builds on (Alert Dialog, Avatar, Button, Checkbox, Dropdown Menu and 11 more) and the npm packages lucide-react and motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/file-list.

How does File List behave on phones?

When the list is narrower than 448px (a phone, a sidebar card) download moves into the ⋯ menu and uploaders show as a face only; on a phone the menu opens as a bottom sheet, and a long press opens it too.

See also

File UploadFile typeslibListProgressEmpty State

Used in

CRM Contact Page

More React data display components

FolderGanttJSON ViewerLog ViewerMarkdownPresence
All 23 React data display components

Articles using this component

  • React File Upload: Drag and Drop, Paste, Camera, Progress

    Component guides · Oct 16, 2026 · 11 min read

PreviousDiff ViewerNext File manager

Documents

Tech Solutions Inc.

8 files · 62 MB
Invoice 2026-0412.pdf248 KB·09/22/2026, 11:20 AM·Olivia Bennett
Services agreement.docx86 KB·09/18/2026, 9:05 AM·Emma Carter
Sales report Q3 2026.xlsx1.2 MB·09/24/2026, 10:12 AM·Liam Walker
Quote deck #Q-2026-118.pptx5.6 MB·09/15/2026, 2:30 PM·Mia Turner
Chicago office lobby.jpg2.3 MB·09/23/2026, 4:02 PM·James Miller
Chicago office meeting room.jpg1.9 MB·09/23/2026, 4:02 PM·James Miller
Chicago office desks.jpg3 MB·09/23/2026, 4:03 PM·James Miller
Documents archive 2025.zip48 MB·08/30/2026, 12:00 PM·Ryan Brooks
Admin ID scan.pdf
64% · 2.4 of 3.8 MB
Office tour video.movThe file is over 25 MB

Click a photo to preview it; Delete on a focused row asks first