File List Component

The FileList component displays files in a beautiful grid or list view with built-in sorting, search, pagination, and file actions.

Basic Usage

import { FileList } from '@dropper/react'

function App() {
  return (
    <FileList
      onFileClick={(file) => console.log('Clicked:', file)}
    />
  )
}

Props

interface FileListProps {
  folderId?: string
  view?: 'grid' | 'list'
  selectable?: boolean
  searchable?: boolean
  sortBy?: 'name' | 'size' | 'createdAt' | 'updatedAt'
  sortOrder?: 'asc' | 'desc'
  actions?: Array<'download' | 'delete' | 'view'>
  className?: string
  onFileClick?: (file: FileResponseDto) => void
  onFileSelect?: (files: FileResponseDto[]) => void
  enablePagination?: boolean
  pageSize?: number
}

folderId

Display files from a specific folder:

<FileList folderId="folder_abc123" />

view

Choose between grid or list view:

{/* Grid view (default) */}
<FileList view="grid" />

{/* List view */}
<FileList view="list" />

selectable

Enable file selection with checkboxes:

<FileList
  selectable
  onFileSelect={(files) => {
    console.log('Selected files:', files)
  }}
/>

searchable

Enable search functionality:

{/* With search (default) */}
<FileList searchable />

{/* Without search */}
<FileList searchable={false} />

sortBy

Default sort field:

{/* Sort by creation date (default) */}
<FileList sortBy="createdAt" />

{/* Sort by name */}
<FileList sortBy="name" />

{/* Sort by size */}
<FileList sortBy="size" />

{/* Sort by update date */}
<FileList sortBy="updatedAt" />

sortOrder

Default sort direction:

{/* Descending (default) */}
<FileList sortOrder="desc" />

{/* Ascending */}
<FileList sortOrder="asc" />

actions

Available file actions:

{/* All actions (default) */}
<FileList actions={['download', 'delete', 'view']} />

{/* View and download only */}
<FileList actions={['view', 'download']} />

{/* No actions */}
<FileList actions={[]} />

enablePagination

Enable "Show More" pagination:

{/* Disabled (default) */}
<FileList enablePagination={false} />

{/* Enabled with default page size (20) */}
<FileList enablePagination />

{/* Custom page size */}
<FileList enablePagination pageSize={50} />

Event Handlers

onFileClick

Called when a file is clicked:

<FileList
  onFileClick={(file) => {
    console.log('Clicked file:', file.originalFilename)
    console.log('URL:', file.url)
    openFilePreview(file)
  }}
/>

onFileSelect

Called when file selection changes:

<FileList
  selectable
  onFileSelect={(files) => {
    console.log(`Selected ${files.length} files`)
    setSelectedFiles(files)
  }}
/>

Complete Examples

Basic File Gallery

import { FileList } from '@dropper/react'

function FileGallery() {
  return (
    <FileList
      view="grid"
      sortBy="createdAt"
      sortOrder="desc"
      onFileClick={(file) => {
        window.open(file.url, '_blank')
      }}
    />
  )
}

Image Gallery

import { FileList } from '@dropper/react'
import { useState } from 'react'

function ImageGallery() {
  const [selectedImage, setSelectedImage] = useState(null)
  
  return (
    <div>
      <FileList
        view="grid"
        searchable
        onFileClick={(file) => {
          setSelectedImage(file)
        }}
      />
      
      {selectedImage && (
        <div className="modal">
          <img src={selectedImage.url} alt={selectedImage.originalFilename} />
          <button onClick={() => setSelectedImage(null)}>Close</button>
        </div>
      )}
    </div>
  )
}

Folder Files

import { FileList } from '@dropper/react'
import { useState } from 'react'

function FolderFiles() {
  const [currentFolder, setCurrentFolder] = useState('folder_123')
  
  return (
    <div>
      <h2>Files in Folder</h2>
      
      <FileList
        folderId={currentFolder}
        view="list"
        sortBy="name"
        sortOrder="asc"
        actions={['view', 'download', 'delete']}
      />
    </div>
  )
}

Selectable Files

import { FileList } from '@dropper/react'
import { useState } from 'react'

function SelectableFiles() {
  const [selectedFiles, setSelectedFiles] = useState([])
  
  const handleBulkDelete = async () => {
    // Delete selected files
    console.log('Deleting:', selectedFiles)
  }
  
  const handleBulkDownload = () => {
    selectedFiles.forEach((file) => {
      window.open(file.url, '_blank')
    })
  }
  
  return (
    <div>
      {selectedFiles.length > 0 && (
        <div className="actions">
          <button onClick={handleBulkDownload}>
            Download {selectedFiles.length} files
          </button>
          <button onClick={handleBulkDelete}>
            Delete {selectedFiles.length} files
          </button>
        </div>
      )}
      
      <FileList
        selectable
        onFileSelect={setSelectedFiles}
      />
    </div>
  )
}

Paginated List

import { FileList } from '@dropper/react'

function PaginatedFileList() {
  return (
    <FileList
      enablePagination
      pageSize={20}
      view="grid"
      sortBy="createdAt"
      sortOrder="desc"
    />
  )
}

Document Library

import { FileList } from '@dropper/react'
import { useState } from 'react'

function DocumentLibrary() {
  const [viewMode, setViewMode] = useState<'grid' | 'list'>('list')
  
  return (
    <div>
      <div className="toolbar">
        <button onClick={() => setViewMode('grid')}>Grid</button>
        <button onClick={() => setViewMode('list')}>List</button>
      </div>
      
      <FileList
        view={viewMode}
        sortBy="name"
        searchable
        actions={['view', 'download']}
        onFileClick={(file) => {
          // Open document viewer
          openDocumentViewer(file)
        }}
      />
    </div>
  )
}

Media Manager

import { FileList } from '@dropper/react'
import { useState } from 'react'

function MediaManager() {
  const [selectedFiles, setSelectedFiles] = useState([])
  const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')
  
  return (
    <div className="media-manager">
      <div className="toolbar">
        <div className="view-toggle">
          <button
            onClick={() => setViewMode('grid')}
            className={viewMode === 'grid' ? 'active' : ''}
          >
            Grid
          </button>
          <button
            onClick={() => setViewMode('list')}
            className={viewMode === 'list' ? 'active' : ''}
          >
            List
          </button>
        </div>
        
        {selectedFiles.length > 0 && (
          <div className="bulk-actions">
            <span>{selectedFiles.length} selected</span>
            <button>Download All</button>
            <button>Delete All</button>
          </div>
        )}
      </div>
      
      <FileList
        view={viewMode}
        selectable
        searchable
        enablePagination
        pageSize={30}
        sortBy="createdAt"
        sortOrder="desc"
        actions={['view', 'download', 'delete']}
        onFileSelect={setSelectedFiles}
        onFileClick={(file) => {
          console.log('Clicked:', file.originalFilename)
        }}
      />
    </div>
  )
}

Features

Grid View

  • Responsive grid layout
  • Image thumbnails
  • File type icons
  • File name and size
  • Action menu

List View

  • Compact list layout
  • Sortable columns
  • File details
  • Quick actions
  • Efficient for large lists

Search

  • Real-time search
  • Search by filename
  • Debounced input
  • Clear search button

Sorting

  • Sort by name, size, or date
  • Ascending/descending order
  • Visual sort indicators
  • Persistent sort state

File Actions

  • View: Preview file
  • Download: Download file
  • Delete: Delete file with confirmation

Selection

  • Multi-select with checkboxes
  • Select all/none
  • Bulk actions
  • Selection count

Pagination

  • "Show More" button
  • Infinite scroll support
  • Configurable page size
  • Loading states

Styling

Custom Class Name

<FileList
  className="my-custom-file-list"
/>

Themed Component

Uses theme from DropperProvider:

<DropperProvider
  publishableKey="pk_dropper_test_xxx"
  theme={{ primary: '#3b82f6' }}
>
  <FileList /> {/* Uses blue theme */}
</DropperProvider>

Architecture

The component follows a three-layer architecture:

1. API Layer (useFileListApi)

Handles data fetching and mutations:

const { files, isLoading, deleteFile } = useFileListApi({
  folderId,
  sortBy,
  sortOrder,
})

2. Logic Layer (useFileListLogic)

Manages state and computed data:

const {
  view,
  searchQuery,
  selectedFiles,
  filteredFiles,
  toggleSort,
} = useFileListLogic({
  files,
  initialView,
})

3. UI Layer (Component)

Renders the interface:

<FileList {...props} />

Accessibility

The component is fully accessible:

  • Keyboard navigation
  • Screen reader support
  • ARIA labels
  • Focus management
  • Semantic HTML

Best Practices

1. Provide Event Handlers

<FileList
  onFileClick={(file) => {
    // Handle click
  }}
  onFileSelect={(files) => {
    // Handle selection
  }}
/>

2. Use Pagination for Large Lists

<FileList
  enablePagination
  pageSize={50}
/>

3. Enable Search

<FileList searchable />

4. Choose Appropriate View

{/* Grid for images */}
<FileList view="grid" />

{/* List for documents */}
<FileList view="list" />

5. Limit Actions

{/* Read-only */}
<FileList actions={['view']} />

{/* Full control */}
<FileList actions={['view', 'download', 'delete']} />

TypeScript Support

The component is fully typed:

import type { FileListProps, FileResponseDto } from '@dropper/react'

const props: FileListProps = {
  view: 'grid',
  sortBy: 'createdAt',
  onFileClick: (file: FileResponseDto) => {
    console.log(file.url)
  },
}

<FileList {...props} />

Performance

The component is optimized for performance:

  • React Query Caching: Files are cached automatically
  • Debounced Search: Search input is debounced
  • Virtual Scrolling: Efficient rendering for large lists
  • Memoization: Computed values are memoized
  • Lazy Loading: Images load on demand

Next Steps