React Components
View uploaded documents
The FileViewer component provides a file browser and management interface for your uploaded documents. Users can view files, see details, and manage their document library.
bashnpm install @easyrag/react-components
tsximport { FileViewer } from '@easyrag/react-components'; function App() { return ( <FileViewer token={yourToken} datasetId="my-dataset" /> ); }
| Prop | Type | Description |
|---|---|---|
token | string | Authentication token (frontend token recommended) |
datasetId | string | Dataset ID to browse |
| Prop | Type | Default | Description |
|---|---|---|---|
apiUrl | string | https://api.easyrag.com/v1 | API base URL |
filters | array | [] | Metadata filters to apply |
files | array | undefined | Pre-loaded files (skips auto-load) |
autoLoad | boolean | true | Auto-load files on mount |
layout | 'split' | 'list' | 'grid' | 'split' | Display layout |
showSize | boolean | true | Show file sizes |
showExtension | boolean | true | Show file extensions |
showMetadata | boolean | false | Show metadata panel |
showTranscription | boolean | true | Show transcriptions (audio/video) |
showDeleteButton | boolean | true | Show delete file button |
showOpenButton | boolean | true | Show open file button |
theme | 'default' | 'minimal' | 'custom' | 'default' | Visual theme |
className | string | '' | Additional CSS classes |
customStyles | object | {} | Custom CSS class overrides |
labels | object | {} | Custom text labels |
showPoweredBy | boolean | true | Show "Powered by EasyRAG" |
poweredByUrl | string | https://easyrag.com | Powered by link URL |
| Prop | Type | Description |
|---|---|---|
onFileSelect | (file: FileMetadata) => void | Called when file is selected |
onFileDelete | (fileId: string) => void | Called when file is deleted |
onFilesLoad | (files: FileMetadata[]) => void | Called when files are loaded |
onError | (error: Error) => void | Called when an error occurs |
tsx<FileViewer token={token} datasetId="my-dataset" />
File list on left, details panel on right:
tsx<FileViewer token={token} datasetId="my-dataset" layout="split" showMetadata={true} />
Files only, no details panel:
tsx<FileViewer token={token} datasetId="my-dataset" layout="list" showSize={true} showExtension={true} />
Grid of file cards:
tsx<FileViewer token={token} datasetId="my-dataset" layout="grid" />
Show only specific files:
tsx<FileViewer token={token} datasetId="shared-dataset" filters={[ { key: 'userId', match: { value: currentUser.id } }, { key: 'department', match: { value: 'engineering' } } ]} />
No delete button:
tsx<FileViewer token={token} datasetId="my-dataset" showDeleteButton={false} showOpenButton={true} />
tsx<FileViewer token={token} datasetId="my-dataset" onFileSelect={(file) => { console.log('Selected file:', file.originalName); }} onFileDelete={(fileId) => { console.log('Deleted file:', fileId); toast.success('File deleted'); }} onFilesLoad={(files) => { console.log(`Loaded ${files.length} files`); }} onError={(error) => { console.error('File viewer error:', error); toast.error('Failed to load files'); }} />
Pass files manually (skips auto-load):
tsxfunction MyFileViewer() { const [files, setFiles] = useState([]); useEffect(() => { // Load files yourself loadFiles().then(setFiles); }, []); return ( <FileViewer token={token} datasetId="my-dataset" files={files} autoLoad={false} /> ); }
tsx<FileViewer token={token} datasetId="my-dataset" theme="custom" customStyles={{ container: 'my-viewer-wrapper', fileList: 'my-file-list', fileItem: 'my-file-item', fileItemActive: 'my-active-item', detailsPanel: 'my-details-panel', }} />
tsx<FileViewer token={token} datasetId="my-dataset" labels={{ title: 'Your Documents', emptyState: 'No files uploaded yet', selectFile: 'Select a file to view details', openFile: 'View File', deleteFile: 'Remove', confirmDelete: 'Are you sure you want to delete this file?', }} />
Best for: Detailed file inspection
tsx<FileViewer layout="split" />
Shows:
Best for: Quick browsing
tsx<FileViewer layout="list" />
Shows:
Best for: Visual browsing
tsx<FileViewer layout="grid" />
Shows:
Modern, polished design with EasyRAG branding:
tsx<FileViewer token={token} datasetId="dataset" theme="default" />
Clean, simple styling:
tsx<FileViewer token={token} datasetId="dataset" theme="minimal" />
Full control over styling:
tsx<FileViewer token={token} datasetId="dataset" theme="custom" customStyles={{ container: 'bg-white rounded-lg shadow-lg p-6', fileList: 'border border-gray-300 divide-y', fileItem: 'p-3 hover:bg-gray-50 cursor-pointer', fileItemActive: 'bg-blue-50 border-l-4 border-blue-600', detailsPanel: 'border border-gray-300 rounded p-4', }} />
Full TypeScript support included:
typescriptimport type { FileViewerProps, FileMetadata } from '@easyrag/react-components'; interface FileMetadata { fileId: string; originalName: string; extension?: string; size?: number; filePath?: string; created?: string; mimeType?: string; transcriptionText?: string; transcriptionSrt?: string; permanentUrl?: string; extraMeta?: Record<string, any>; } const props: FileViewerProps = { token: 'your-token', datasetId: 'my-dataset', layout: 'split', onFileSelect: (file: FileMetadata) => { console.log(file); } };
Target specific elements with CSS:
css/* Container */ .easyrag-file-viewer { } /* File list */ .easyrag-file-viewer .file-list { } /* Individual file item */ .easyrag-file-viewer .file-item { } /* Active/selected file */ .easyrag-file-viewer .file-item-active { } /* Details panel */ .easyrag-file-viewer .details-panel { } /* Buttons */ .easyrag-file-viewer button { }
Refresh viewer after upload:
tsxfunction DocumentManager() { const [refreshKey, setRefreshKey] = useState(0); return ( <> <FileUpload token={token} datasetId="dataset" onUploadComplete={() => { setRefreshKey(prev => prev + 1); }} /> <FileViewer key={refreshKey} token={token} datasetId="dataset" layout="split" /> </> ); }
Highlight searched files:
tsxfunction SearchableFileList() { const [searchResults, setSearchResults] = useState([]); const [selectedFile, setSelectedFile] = useState(null); return ( <> <SearchBox token={token} datasetId="dataset" onResults={(results) => { setSearchResults(results); // Get fileIds from results const fileIds = results.map(r => r.metadata.fileId); console.log('Results from files:', fileIds); }} /> <FileViewer token={token} datasetId="dataset" onFileSelect={(file) => setSelectedFile(file)} /> </> ); }
tsxfunction FileManagementApp() { const [files, setFiles] = useState([]); const [filter, setFilter] = useState(''); return ( <div className="space-y-6"> {/* Upload */} <FileUpload token={token} datasetId="dataset" onUploadComplete={(result) => { setFiles(prev => [...prev, ...result.files]); }} /> {/* Filter */} <input type="text" placeholder="Filter by name..." value={filter} onChange={(e) => setFilter(e.target.value)} /> {/* View */} <FileViewer token={token} datasetId="dataset" files={files.filter(f => f.originalName.includes(filter) )} layout="split" showMetadata={true} onFileDelete={(fileId) => { setFiles(prev => prev.filter(f => f.fileId !== fileId)); }} /> </div> ); }
tsx<FileViewer token={token} datasetId="company-docs" layout="grid" filters={[ { key: 'department', match: { value: user.department } } ]} showMetadata={true} />
tsx<FileViewer token={token} datasetId="media-files" layout="grid" showTranscription={true} filters={[ { key: 'type', match: { value: 'audio' } } ]} />
tsx<FileViewer token={token} datasetId="my-files" layout="split" filters={[ { key: 'userId', match: { value: currentUser.id } } ]} showSize={true} showDeleteButton={true} />
Generate short-lived tokens from your backend:
typescript// Backend app.post('/api/tokens/create', authenticate, async (req, res) => { const token = signFrontendToken({ customerId: req.user.id, datasetId: req.body.datasetId, ttlSeconds: 3600 }); res.json({ token }); });
Always filter to user's own files:
tsx<FileViewer token={token} datasetId="shared-dataset" filters={[ { key: 'userId', match: { value: currentUser.id } } ]} />
tsx<FileViewer token={token} datasetId="dataset" onFileSelect={(file) => { // Update URL router.push(`/files/${file.fileId}`); // Track analytics analytics.track('file_viewed', { fileId: file.fileId, fileName: file.originalName }); }} />
The component shows a browser confirm dialog by default. Customize the message:
tsx<FileViewer token={token} datasetId="dataset" labels={{ confirmDelete: 'Are you sure? This cannot be undone.' }} onFileDelete={(fileId) => { // Clean up related data deleteRelatedChunks(fileId); toast.success('File deleted successfully'); }} />
tsx// Let users choose const [layout, setLayout] = useState('split'); <select value={layout} onChange={(e) => setLayout(e.target.value)}> <option value="split">Split</option> <option value="list">List</option> <option value="grid">Grid</option> </select> <FileViewer layout={layout} {...props} />
The FileViewer component includes:
Need help? Contact us at: