Folder Browser
The FolderBrowser component provides a tree view for navigating and managing folder hierarchies with support for creating, renaming, and deleting folders.
Basic Usage
import { FolderBrowser } from '@dropper/react'
function App() {
return (
<FolderBrowser
onFolderChange={(folderId) => {
console.log('Current folder:', folderId)
}}
/>
)
}
Props
interface FolderBrowserProps {
initialPath?: string
showFiles?: boolean
allowCreate?: boolean
allowDelete?: boolean
allowRename?: boolean
className?: string
onFolderChange?: (folderId: string) => void
onFileClick?: (file: FileResponseDto) => void
}
initialPath
Set the initial folder path:
{/* Start at root (default) */}
<FolderBrowser initialPath="/" />
{/* Start at specific folder */}
<FolderBrowser initialPath="/Documents/2024" />
showFiles
Display files in the current folder:
{/* Show files (default) */}
<FolderBrowser showFiles />
{/* Folders only */}
<FolderBrowser showFiles={false} />
allowCreate
Enable folder creation:
{/* Allow creation (default) */}
<FolderBrowser allowCreate />
{/* Read-only */}
<FolderBrowser allowCreate={false} />
allowDelete
Enable folder deletion:
{/* Allow deletion (default) */}
<FolderBrowser allowDelete />
{/* Prevent deletion */}
<FolderBrowser allowDelete={false} />
allowRename
Enable folder renaming:
{/* Allow renaming (default) */}
<FolderBrowser allowRename />
{/* Prevent renaming */}
<FolderBrowser allowRename={false} />
Event Handlers
onFolderChange
Called when the current folder changes:
<FolderBrowser
onFolderChange={(folderId) => {
console.log('Navigated to folder:', folderId)
loadFolderContents(folderId)
}}
/>
onFileClick
Called when a file is clicked:
<FolderBrowser
showFiles
onFileClick={(file) => {
console.log('Clicked file:', file.originalFilename)
openFile(file)
}}
/>
Complete Examples
Basic Folder Navigation
import { FolderBrowser } from '@dropper/react'
import { useState } from 'react'
function FolderNavigation() {
const [currentFolder, setCurrentFolder] = useState(null)
return (
<div>
<h2>Browse Folders</h2>
<FolderBrowser
onFolderChange={(folderId) => {
setCurrentFolder(folderId)
console.log('Current folder:', folderId)
}}
/>
{currentFolder && (
<p>Current folder ID: {currentFolder}</p>
)}
</div>
)
}
File Explorer
import { FolderBrowser, FileList } from '@dropper/react'
import { useState } from 'react'
function FileExplorer() {
const [currentFolder, setCurrentFolder] = useState(null)
return (
<div className="flex gap-4">
{/* Left sidebar: Folder tree */}
<div className="w-64 border-r">
<FolderBrowser
showFiles={false}
onFolderChange={setCurrentFolder}
/>
</div>
{/* Right panel: File list */}
<div className="flex-1">
<FileList
folderId={currentFolder}
view="list"
/>
</div>
</div>
)
}
Document Manager
import { FolderBrowser } from '@dropper/react'
import { useState } from 'react'
function DocumentManager() {
const [selectedFile, setSelectedFile] = useState(null)
return (
<div className="document-manager">
<div className="sidebar">
<h3>Folders</h3>
<FolderBrowser
initialPath="/Documents"
showFiles
allowCreate
allowRename
allowDelete
onFileClick={(file) => {
setSelectedFile(file)
}}
/>
</div>
<div className="content">
{selectedFile ? (
<div>
<h2>{selectedFile.originalFilename}</h2>
<iframe src={selectedFile.url} />
</div>
) : (
<p>Select a file to view</p>
)}
</div>
</div>
)
}
Read-Only Browser
import { FolderBrowser } from '@dropper/react'
function ReadOnlyBrowser() {
return (
<FolderBrowser
allowCreate={false}
allowDelete={false}
allowRename={false}
onFolderChange={(folderId) => {
console.log('Viewing folder:', folderId)
}}
/>
)
}
Media Library Browser
import { FolderBrowser, FileList } from '@dropper/react'
import { useState } from 'react'
function MediaLibraryBrowser() {
const [currentFolder, setCurrentFolder] = useState(null)
const [selectedFiles, setSelectedFiles] = useState([])
return (
<div className="media-library">
<div className="flex h-screen">
{/* Folder tree */}
<div className="w-64 border-r overflow-auto">
<div className="p-4">
<h3 className="font-semibold mb-4">Folders</h3>
<FolderBrowser
showFiles={false}
allowCreate
onFolderChange={setCurrentFolder}
/>
</div>
</div>
{/* File grid */}
<div className="flex-1 overflow-auto">
<div className="p-4">
<h3 className="font-semibold mb-4">
{currentFolder ? 'Folder Contents' : 'All Files'}
</h3>
<FileList
folderId={currentFolder}
view="grid"
selectable
onFileSelect={setSelectedFiles}
/>
</div>
</div>
</div>
{/* Selection toolbar */}
{selectedFiles.length > 0 && (
<div className="fixed bottom-0 left-0 right-0 bg-white border-t p-4">
<div className="flex items-center justify-between">
<span>{selectedFiles.length} files selected</span>
<div className="flex gap-2">
<button>Download</button>
<button>Move</button>
<button>Delete</button>
</div>
</div>
</div>
)}
</div>
)
}
Folder Picker
import { FolderBrowser } from '@dropper/react'
import { useState } from 'react'
function FolderPicker({ onSelect }) {
const [selectedFolder, setSelectedFolder] = useState(null)
return (
<div className="folder-picker">
<h3>Select a folder</h3>
<FolderBrowser
showFiles={false}
allowCreate
onFolderChange={(folderId) => {
setSelectedFolder(folderId)
}}
/>
<div className="actions">
<button
onClick={() => onSelect(selectedFolder)}
disabled={!selectedFolder}
>
Select Folder
</button>
<button onClick={() => onSelect(null)}>
Cancel
</button>
</div>
</div>
)
}
Features
Tree View
- Hierarchical folder structure
- Expand/collapse folders
- Visual indentation
- Folder icons
Folder Actions
- Create: Add new folders
- Rename: Rename existing folders
- Delete: Remove folders (with confirmation)
- Navigate: Click to navigate
File Display
- Show files in current folder
- File icons and names
- Click to open files
- File count indicators
Navigation
- Breadcrumb navigation
- Home button (root)
- Parent folder navigation
- Deep linking support
Styling
Custom Class Name
<FolderBrowser
className="my-custom-browser"
/>
Themed Component
Uses theme from DropperProvider:
<DropperProvider
publishableKey="pk_dropper_test_xxx"
theme={{ primary: '#10b981' }}
>
<FolderBrowser /> {/* Uses green theme */}
</DropperProvider>
Architecture
The component uses React Query for data management:
Folder Fetching
const { data: folders } = useQuery({
queryKey: ['folders'],
queryFn: () => client.listFolders(),
})
File Fetching
const { data: files } = useQuery({
queryKey: ['files', currentFolderId],
queryFn: () => client.listFiles({ folderId: currentFolderId }),
})
Mutations
const createMutation = useMutation({
mutationFn: (name) => client.createFolder({ name }),
onSuccess: () => queryClient.invalidateQueries(['folders']),
})
Accessibility
The component is fully accessible:
- Keyboard navigation (Arrow keys, Enter, Escape)
- Screen reader support
- ARIA tree role
- Focus management
- Semantic HTML
Best Practices
1. Provide Event Handlers
<FolderBrowser
onFolderChange={(folderId) => {
// Update app state
}}
onFileClick={(file) => {
// Handle file click
}}
/>
2. Combine with FileList
const [folder, setFolder] = useState(null)
<div className="flex">
<FolderBrowser onFolderChange={setFolder} />
<FileList folderId={folder} />
</div>
3. Set Appropriate Permissions
{/* Admin view */}
<FolderBrowser
allowCreate
allowRename
allowDelete
/>
{/* User view */}
<FolderBrowser
allowCreate={false}
allowRename={false}
allowDelete={false}
/>
4. Handle Empty States
<FolderBrowser
onFolderChange={(folderId) => {
if (!folderId) {
showMessage('No folder selected')
}
}}
/>
Common Patterns
Split View
<div className="flex">
<FolderBrowser
className="w-64"
showFiles={false}
onFolderChange={setCurrentFolder}
/>
<FileList
className="flex-1"
folderId={currentFolder}
/>
</div>
Modal Picker
function FolderPickerModal({ open, onClose, onSelect }) {
return (
<Modal open={open} onClose={onClose}>
<FolderBrowser
showFiles={false}
onFolderChange={(folderId) => {
onSelect(folderId)
onClose()
}}
/>
</Modal>
)
}
Breadcrumb Navigation
The component includes built-in breadcrumb navigation showing the current path.
TypeScript Support
The component is fully typed:
import type { FolderBrowserProps, FileResponseDto } from '@dropper/react'
const props: FolderBrowserProps = {
initialPath: '/',
showFiles: true,
onFolderChange: (folderId: string) => {
console.log(folderId)
},
onFileClick: (file: FileResponseDto) => {
console.log(file.url)
},
}
<FolderBrowser {...props} />
Performance
The component is optimized for performance:
- React Query Caching: Folders are cached
- Lazy Loading: Folders load on expand
- Optimistic Updates: UI updates immediately
- Debounced Actions: Prevents excessive API calls
Next Steps
- File List Component - Display files
- File Upload Component - Upload to folders
- useDropper Hook - Access Dropper client