Media Library

The MediaLibrary component is a complete, all-in-one media management solution that combines file upload, browsing, folder navigation, and file actions into a single powerful component.

Basic Usage

import { MediaLibrary } from '@dropper/react'

function App() {
  return <MediaLibrary />
}

Props

interface MediaLibraryProps {
  isSelectionMode?: boolean
  onFileSelect?: (file: FileResponseDto) => void
  allowedTypes?: string[]
  hideUpload?: boolean
  initialFolderId?: string | null
  emptyMessage?: string
  debug?: boolean
  className?: string
  uploadProgressPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
  enablePagination?: boolean
  pageSize?: number
}

isSelectionMode

Enable selection mode for file picking:

<MediaLibrary
  isSelectionMode
  onFileSelect={(file) => {
    console.log('Selected:', file)
  }}
/>

onFileSelect

Callback when a file is selected (in selection mode):

<MediaLibrary
  isSelectionMode
  onFileSelect={(file) => {
    setSelectedFile(file)
    closeModal()
  }}
/>

allowedTypes

Filter files by MIME type in selection mode:

{/* Images only */}
<MediaLibrary
  isSelectionMode
  allowedTypes={['image/*']}
  onFileSelect={(file) => console.log('Selected image:', file)}
/>

{/* Specific types */}
<MediaLibrary
  isSelectionMode
  allowedTypes={['image/jpeg', 'image/png', 'video/mp4']}
/>

hideUpload

Hide upload functionality:

{/* Show upload (default) */}
<MediaLibrary />

{/* Hide upload */}
<MediaLibrary hideUpload />

initialFolderId

Start at a specific folder:

<MediaLibrary initialFolderId="folder_abc123" />

emptyMessage

Custom message when no files exist:

<MediaLibrary
  emptyMessage="No media files yet. Upload your first file to get started!"
/>

uploadProgressPosition

Position of the upload progress panel:

{/* Bottom right (default) */}
<MediaLibrary uploadProgressPosition="bottom-right" />

{/* Other positions */}
<MediaLibrary uploadProgressPosition="top-left" />
<MediaLibrary uploadProgressPosition="top-right" />
<MediaLibrary uploadProgressPosition="bottom-left" />

enablePagination

Enable "Show More" pagination:

{/* Enabled (default) */}
<MediaLibrary enablePagination />

{/* Disabled */}
<MediaLibrary enablePagination={false} />

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

Complete Examples

Full Media Manager

import { MediaLibrary } from '@dropper/react'

function MediaManager() {
  return (
    <div className="h-screen">
      <MediaLibrary />
    </div>
  )
}

File Picker Modal

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

function FilePickerModal({ open, onClose }) {
  const [selectedFile, setSelectedFile] = useState(null)
  
  return (
    <Modal open={open} onClose={onClose}>
      <div className="h-[600px]">
        <MediaLibrary
          isSelectionMode
          onFileSelect={(file) => {
            setSelectedFile(file)
            onClose(file)
          }}
        />
      </div>
    </Modal>
  )
}

Image Picker

import { MediaLibrary } from '@dropper/react'

function ImagePicker({ onSelect }) {
  return (
    <MediaLibrary
      isSelectionMode
      allowedTypes={['image/*']}
      onFileSelect={(file) => {
        onSelect(file.url)
      }}
    />
  )
}

Document Library

import { MediaLibrary } from '@dropper/react'

function DocumentLibrary() {
  return (
    <div className="container mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">Document Library</h1>
      
      <MediaLibrary
        allowedTypes={['.pdf', '.doc', '.docx', '.txt']}
        emptyMessage="No documents yet. Upload your first document!"
        enablePagination
        pageSize={30}
      />
    </div>
  )
}

Read-Only Gallery

import { MediaLibrary } from '@dropper/react'

function ReadOnlyGallery() {
  return (
    <MediaLibrary
      hideUpload
      allowedTypes={['image/*', 'video/*']}
    />
  )
}

CMS Media Selector

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

function CMSMediaSelector({ fieldName, onSelect }) {
  const [isOpen, setIsOpen] = useState(false)
  const [selectedMedia, setSelectedMedia] = useState(null)
  
  return (
    <div>
      <label>{fieldName}</label>
      
      {selectedMedia && (
        <div className="preview">
          <img src={selectedMedia.url} alt={selectedMedia.originalFilename} />
          <button onClick={() => setSelectedMedia(null)}>Remove</button>
        </div>
      )}
      
      <button onClick={() => setIsOpen(true)}>
        Select Media
      </button>
      
      {isOpen && (
        <Modal open={isOpen} onClose={() => setIsOpen(false)}>
          <MediaLibrary
            isSelectionMode
            allowedTypes={['image/*']}
            onFileSelect={(file) => {
              setSelectedMedia(file)
              onSelect(file)
              setIsOpen(false)
            }}
          />
        </Modal>
      )}
    </div>
  )
}

Features

File Management

  • Upload: Drag-and-drop or click to upload
  • Browse: Grid and list views
  • Search: Real-time file search
  • Sort: Sort by name, size, or date
  • Filter: Filter by file type
  • Preview: Preview images and videos
  • Download: Download files
  • Delete: Delete files with confirmation

Folder Management

  • Navigate: Browse folder hierarchy
  • Create: Create new folders
  • Rename: Rename folders
  • Delete: Delete folders
  • Breadcrumbs: Navigate with breadcrumbs

Upload Features

  • Drag & Drop: Drag files to upload
  • Multiple Files: Upload multiple files at once
  • Progress Tracking: Real-time upload progress
  • Queue Management: Manage upload queue
  • Retry: Retry failed uploads
  • Cancel: Cancel in-progress uploads

View Options

  • Grid View: Visual grid layout
  • List View: Compact list layout
  • Toggle: Switch between views
  • Responsive: Adapts to screen size

Selection Mode

  • File Picker: Use as a file picker
  • Type Filtering: Filter by MIME type
  • Single Selection: Select one file
  • Quick Select: Click to select

Architecture

The MediaLibrary orchestrates multiple components:

Components Used

  1. BreadcrumbNavigation: Folder path navigation
  2. MediaAssetGrid: File and folder display
  3. CreateFolderModal: Folder creation
  4. FileUploadModal: File upload
  5. MediaPreviewModal: File preview
  6. UploadProgress: Upload progress tracking
  7. LoadMorePagination: Pagination

Hooks Used

  1. useFileListApi: File data fetching
  2. useInfiniteFileListApi: Paginated file fetching
  3. useFolderBrowserApi: Folder data fetching
  4. useMediaLibraryLogic: State management
  5. useUploadQueue: Upload queue management

Styling

Custom Class Name

<MediaLibrary className="my-custom-library" />

Themed Component

Uses theme from DropperProvider:

<DropperProvider
  publishableKey="pk_dropper_test_xxx"
  theme={{
    primary: '#3b82f6',
    radius: 'lg',
  }}
>
  <MediaLibrary />
</DropperProvider>

Keyboard Shortcuts

  • Arrow Keys: Navigate files
  • Enter: Open/select file
  • Delete: Delete selected file
  • Escape: Close modals
  • Ctrl/Cmd + A: Select all (when selectable)

Accessibility

The component is fully accessible:

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

Best Practices

1. Use in Full-Screen Context

<div className="h-screen">
  <MediaLibrary />
</div>

2. Provide Selection Callback

<MediaLibrary
  isSelectionMode
  onFileSelect={(file) => {
    // Handle selection
  }}
/>

3. Filter by Type

<MediaLibrary
  allowedTypes={['image/*']}
/>

4. Enable Pagination

<MediaLibrary
  enablePagination
  pageSize={30}
/>

5. Customize Empty State

<MediaLibrary
  emptyMessage="Upload your first file to get started!"
/>

Common Patterns

Modal File Picker

function useFilePicker() {
  const [isOpen, setIsOpen] = useState(false)
  const [selectedFile, setSelectedFile] = useState(null)
  
  const openPicker = () => setIsOpen(true)
  const closePicker = () => setIsOpen(false)
  
  const picker = (
    <Modal open={isOpen} onClose={closePicker}>
      <MediaLibrary
        isSelectionMode
        onFileSelect={(file) => {
          setSelectedFile(file)
          closePicker()
        }}
      />
    </Modal>
  )
  
  return { openPicker, selectedFile, picker }
}

Embedded in CMS

function CMSMediaField({ value, onChange }) {
  const [showPicker, setShowPicker] = useState(false)
  
  return (
    <div>
      {value && (
        <img src={value.url} alt={value.originalFilename} />
      )}
      
      <button onClick={() => setShowPicker(true)}>
        {value ? 'Change' : 'Select'} Media
      </button>
      
      {showPicker && (
        <Modal open onClose={() => setShowPicker(false)}>
          <MediaLibrary
            isSelectionMode
            allowedTypes={['image/*']}
            onFileSelect={(file) => {
              onChange(file)
              setShowPicker(false)
            }}
          />
        </Modal>
      )}
    </div>
  )
}

TypeScript Support

The component is fully typed:

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

const props: MediaLibraryProps = {
  isSelectionMode: true,
  allowedTypes: ['image/*'],
  onFileSelect: (file: FileResponseDto) => {
    console.log(file.url)
  },
}

<MediaLibrary {...props} />

Performance

The component is optimized for performance:

  • React Query Caching: Data is cached automatically
  • Infinite Scrolling: Efficient pagination
  • Lazy Loading: Images load on demand
  • Debounced Search: Search is debounced
  • Memoization: Computed values are memoized

Comparison with Individual Components

Use MediaLibrary When:

  • You need a complete media management solution
  • You want upload, browse, and organize in one component
  • You're building a file picker or media selector
  • You need a ready-to-use solution

Use Individual Components When:

  • You need fine-grained control
  • You're building a custom interface
  • You only need specific functionality
  • You want maximum flexibility

Next Steps