React Components
React components for EasyRAG
EasyRAG provides production-ready React components that make it easy to add RAG capabilities to your application. These components handle authentication, API calls, error handling, and provide beautiful UIs out of the box.
Drag-and-drop file upload with progress tracking, metadata support, and custom chunking options.
Semantic search interface with customizable result display, filtering, and scoring.
AI-powered chat interface with streaming responses, message history, and auto-scroll.
Browse, preview, and manage uploaded files with metadata display and deletion.
Drop components into your React app and they work immediately. No complex setup required.
tsximport { FileUpload } from '@easyrag/react-components'; <FileUpload token={token} datasetId="my-dataset" />
Three built-in themes (default, minimal, custom) and extensive props for styling, labels, and behavior.
tsx<SearchBox token={token} datasetId="my-dataset" theme="minimal" showScore={true} customStyles={{ input: 'my-custom-input', button: 'my-custom-button' }} />
Components support frontend token authentication, keeping your API keys safe on the backend.
tsx// Backend generates short-lived token const token = await generateFrontendToken({ customerId: user.id, datasetId: 'dataset-id', ttlSeconds: 3600 }); // Frontend uses token securely <ChatBox token={token} datasetId="dataset-id" />
Built with TypeScript, includes error handling, loading states, and accessibility features.
Full type definitions included for excellent autocomplete and type safety.
typescriptimport type { FileUploadProps, SearchBoxProps, ChatBoxProps } from '@easyrag/react-components';
bashnpm install @easyrag/react-components
Here's a complete RAG application in just a few lines:
tsximport { FileUpload, SearchBox, ChatBox } from '@easyrag/react-components'; function MyRAGApp() { const [token, setToken] = useState(''); // Get token from your backend useEffect(() => { fetch('/api/tokens/create', { method: 'POST' }) .then(r => r.json()) .then(data => setToken(data.token)); }, []); if (!token) return <div>Loading...</div>; return ( <div className="space-y-8"> {/* Upload documents */} <FileUpload token={token} datasetId="my-dataset" onUploadComplete={() => console.log('Upload complete!')} /> {/* Search documents */} <SearchBox token={token} datasetId="my-dataset" showScore={true} /> {/* Chat with documents */} <ChatBox token={token} datasetId="my-dataset" stream={true} /> </div> ); }
All components support two authentication modes:
Generate a shortβlived token in your backend, then pass it to the React components.
tsimport express from "express"; const router = express.Router(); router.post("/api/easyrag-token", authenticateUser, async (req, res) => { const { datasetId } = req.body; if (!datasetId) { return res.status(400).json({ error: "datasetId is required" }); } const response = await fetch("https://api.easyrag.com/v1/tokens/create", { method: "POST", headers: { Authorization: `Bearer ${process.env.EASY_RAG_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ datasetId, ttlSeconds: 3600 }), }); const data = await response.json(); return res.status(response.ok ? 200 : response.status).json(data); });
tsimport { EasyRAG } from "@easyrag/sdk"; const client = new EasyRAG({ apiKey: process.env.EASY_RAG_KEY!, }); app.post("/api/easyrag-token", authenticateUser, async (req, res) => { const { datasetId } = req.body; if (!datasetId) { return res.status(400).json({ error: "datasetId is required" }); } const result = await client.createToken(datasetId, { ttlSeconds: 3600 }); res.json(result); });
tsimport { NextResponse } from "next/server"; import { EasyRAG } from "@easyrag/sdk"; export const runtime = "nodejs"; // important if the SDK relies on Node APIs const client = new EasyRAG({ apiKey: process.env.EASY_RAG_KEY, }); export async function POST(request: Request) { try { const { datasetId } = await request.json(); if (!datasetId) { return NextResponse.json( { error: "datasetId is required" }, { status: 400 } ); } const result = await client.createToken(datasetId, { ttlSeconds: 3600 }); return NextResponse.json(result, { status: 200 }); } catch (err) { console.error("Token proxy error", err); return NextResponse.json( { error: "Token proxy error" }, { status: 500 } ); } }
tsximport { useEffect, useState } from "react"; import { FileUpload } from "@easyrag/react-components"; function MyRAGApp() { const [token, setToken] = useState<string | null>(null); useEffect(() => { async function fetchToken() { const res = await fetch("/api/easyrag-token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ datasetId: "my-dataset" }), }); const data = await res.json(); setToken(data.token); } fetchToken(); }, []); if (!token) return <div>Loading...</div>; return <FileUpload token={token} datasetId="my-dataset" />; }
For internal tools or development:
tsx<FileUpload token={process.env.EASYRAG_API_KEY} datasetId="my-dataset" />
β οΈ Never expose API keys in production frontends!
Clean, modern design with EasyRAG branding:
tsx<SearchBox token={token} datasetId="dataset" theme="default" />
Lightweight styling, easy to integrate:
tsx<SearchBox token={token} datasetId="dataset" theme="minimal" />
Full control with your own styles:
tsx<SearchBox token={token} datasetId="dataset" theme="custom" customStyles={{ container: 'my-container', input: 'my-input', button: 'my-button', resultCard: 'my-result-card' }} />
Components include an optional "Powered by EasyRAG" watermark:
tsx// Show watermark (default) <ChatBox token={token} datasetId="dataset" showPoweredBy={true} /> // Hide watermark <ChatBox token={token} datasetId="dataset" showPoweredBy={false} /> // Custom URL <ChatBox token={token} datasetId="dataset" poweredByUrl="https://yourcompany.com" />
Components work seamlessly with multi-tenant applications:
tsx// Upload with tenant metadata <FileUpload token={token} datasetId="shared-dataset" metadataBuilder={(file, index) => ({ userId: currentUser.id, department: currentUser.department, uploadedAt: new Date().toISOString() })} /> // Search with tenant filtering <SearchBox token={token} datasetId="shared-dataset" filters={[ { key: 'userId', match: { value: currentUser.id } } ]} />
tsx<ChatBox token={token} datasetId="support-kb" initialMessages={[ { id: 1, role: 'assistant', content: 'Hi! How can I help you today?' } ]} filters={[ { key: 'category', match: { value: 'billing' } } ]} />
tsx<SearchBox token={token} datasetId="company-docs" filters={[ { key: 'department', match: { value: user.department } }, { key: 'confidential', match: { value: false } } ]} showMetadata={true} />
tsx<FileUpload token={token} datasetId="user-documents" maxFiles={5} maxFileSize={10 * 1024 * 1024} // 10MB accept={{ 'application/pdf': ['.pdf'] }} metadataBuilder={(file) => ({ originalName: file.name, uploadedBy: currentUser.email })} />
tsx<FileViewer token={token} datasetId="my-dataset" onFileDelete={(fileId) => { console.log('File deleted:', fileId); refetchFiles(); }} onFileSelect={(file) => { console.log('Selected file:', file); }} />