React component library for displaying HIV drug resistance analysis results
npm install @basic-genomics/hivdb-report

React component library for displaying HIV drug resistance analysis results from the Stanford HIVDB.
- Features
- Installation
- Quick Start
- Usage Modes
- Mode 1: Direct Data Mode
- Mode 2: Sequence Input Mode
- Props
- Advanced Examples
- Configuration
- Data Structure
- API Integration
- Styling
- Browser Support
- TypeScript Support
- Development
- Troubleshooting
- Performance Considerations
- License
- 📊 Complete Report Display - Sequence summary, drug resistance interpretation, mutation analysis
- 🎨 Customizable Theme - Configure primary colors to match your brand
- 📱 Responsive Design - Works on desktop and mobile devices
- 📤 Multiple Export Formats - HTML, CSV, JSON export support
- 🔄 Flexible Data Input - Direct data props or API-based sequence input
- 🔌 API Integration - Built-in support for custom API endpoints
- 📜 Custom Scroll Container - Support for non-window scroll scenarios with anchor navigation
- ⚡ Production Ready - Enterprise-grade code quality, used in production environments
``bash`
npm install @basic-genomics/hivdb-reportor
yarn add @basic-genomics/hivdb-reportor
pnpm add @basic-genomics/hivdb-report
`jsx
import { HIVDBReport } from '@basic-genomics/hivdb-report';
function App() {
// Data from HIVDB GraphQL API
const reportData = {
currentVersion: { text: 'HIVDB_9.8', publishDate: '2025-01-05' },
currentProgramVersion: { text: '3.5.3', publishDate: '2025-01-05' },
sequenceAnalysis: [
{
inputSequence: { header: 'Sample1' },
strain: { name: 'HIV1', display: 'HIV-1' },
bestMatchingSubtype: { display: 'B (2.26%)' },
// ... analysis results
}
]
};
return
}
`
The component supports two mutually exclusive modes:
Provide analysis data directly via props. Best for pre-fetched data or GraphQL integration.
`jsx`
Enable user sequence input with API integration. Best for interactive applications.
#### Request Function Injection
Use callback functions for full control over the request flow. This allows you to:
- Use your own HTTP client (axios, fetch, etc.)
- Integrate with your app's authentication system
- Apply unified error handling
- Use your existing API proxy configuration
`jsx
import { HIVDBReport } from '@basic-genomics/hivdb-report';
function SequenceAnalyzer() {
// Host controls the entire request flow
const handleFetchReport = async (sequenceText) => {
const response = await myApiClient.post('/api/hivdb/analyze', {
sequences: parseSequences(sequenceText),
includeGenes: ['PR', 'RT', 'IN']
});
return response.data;
};
const handleFetchExport = async (sequenceText) => {
const response = await myApiClient.post('/api/hivdb/analyze-full', {
sequences: parseSequences(sequenceText),
includeGenes: ['PR', 'RT', 'IN']
});
return response.data;
};
return (
onFetchReport={handleFetchReport}
onFetchExport={handleFetchExport}
/>
);
}
`
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| Data Props (Mode 1) |
| reportData | object | Conditional* | Analysis data for HTML report display |exportData
| | object | No | Analysis data for CSV/JSON export (includes additional fields) |analysisData
| | object | Conditional* | Legacy: single data source for both report and export |enableSequenceInput
| Sequence Input Props (Mode 2) |
| | boolean | No | Enable sequence input mode (default: false) |sequenceInputPlaceholder
| | string | No | Placeholder text for sequence input |onFetchReport
| Request Function Injection |
| | (sequenceText: string) => Promise | Conditional** | Host-provided function for report requests |onFetchExport
| | (sequenceText: string) => Promise | Conditional** | Host-provided function for export requests |onSequenceChange
| | (sequenceText: string) => void | No | Callback when sequence input changes |config
| General Props |
| | object | No | Configuration overrides (see Configuration section) |scrollContainer
| | HTMLElement \| null | No | Custom scroll container for non-window scroll scenarios |
> *In Mode 1: Either reportData or analysisData is required. onFetchReport
> **In Mode 2: is required for HTML reports; onFetchExport is required for CSV/JSON exports.
Option 1: Separate data sources (Recommended)
Use separate queries optimized for display vs export:
`jsx`
exportData={exportQueryResult} // Full query for export
/>
Option 2: Single data source (Legacy)
Use one complete data object for both:
`jsx`
Best for enterprise applications with existing HTTP clients and error handling:
`jsx
import { HIVDBReport } from '@basic-genomics/hivdb-report';
import { apiClient } from './api'; // Your axios instance with interceptors
function SequenceAnalyzer() {
// Full control over request flow
const handleFetchReport = async (sequenceText) => {
const response = await apiClient.post('/hivdb/analyze', {
sequences: parseSequences(sequenceText),
includeGenes: ['PR', 'RT', 'IN']
});
// Handle GraphQL errors
if (response.data.errors) {
throw new Error(response.data.errors[0]?.message);
}
return response.data.data;
};
const handleFetchExport = async (sequenceText) => {
const response = await apiClient.post('/hivdb/analyze-full', {
sequences: parseSequences(sequenceText),
includeGenes: ['PR', 'RT', 'IN']
});
if (response.data.errors) {
throw new Error(response.data.errors[0]?.message);
}
return response.data.data;
};
return (
onFetchReport={handleFetchReport}
onFetchExport={handleFetchExport}
/>
);
}
`
> Note: The component displays a simulated progress bar during API requests.
When embedding the component in a layout with a custom scrollable container (not window), pass the container element:
`jsx
import { useRef } from 'react';
import { HIVDBReport } from '@basic-genomics/hivdb-report';
function EmbeddedReport() {
const scrollContainerRef = useRef(null);
return (
> Note: The scroll container must have
overflow: auto or overflow: scroll to be scrollable. The component will automatically detect the actual scrollable ancestor if needed.$3
`jsx
import { useQuery } from '@apollo/client';
import { HIVDBReport } from '@basic-genomics/hivdb-report';
import { ANALYZE_SEQUENCES } from './queries';function GraphQLReport({ sequences }) {
const { data, loading, error } = useQuery(ANALYZE_SEQUENCES, {
variables: { sequences }
});
if (loading) return
Loading...;
if (error) return Error: {error.message}; return (
reportData={data.viewer.sequenceAnalysis}
exportData={data.viewer.sequenceAnalysisWithGenes}
/>
);
}
`Configuration
$3
Customize the primary theme color to match your brand:
`jsx
reportData={data}
config={{
themeColors: {
main: '#1565c0', // Primary color (default: #8c1515 red)
mainLighter: '#1e88e5' // Hover/lighter variant (default: #d32424)
}
}}
/>
`Preset Theme Examples:
| Theme | main | mainLighter |
|-------|------|-------------|
| Red (default) |
#8c1515 | #d32424 |
| Blue | #1565c0 | #1e88e5 |
| Green | #2e7d32 | #43a047 |
| Purple | #6a1b9a | #8e24aa |
| Teal | #00796b | #00897b |
| Orange | #e65100 | #f57c00 |$3
`jsx
import { HIVDBReport, defaultConfig } from '@basic-genomics/hivdb-report'; reportData={data}
config={{
// Theme customization
themeColors: {
main: '#1565c0',
mainLighter: '#1e88e5'
},
// Gene display settings
allGenes: ['PR', 'RT', 'IN'],
highlightGenes: ['PR', 'RT', 'IN'],
// Display options
displayMutationScores: ['PR', 'RT', 'IN'],
displaySDRMs: ['PR', 'RT', 'IN'],
// Form settings
formEnableTabs: ['patterns', 'sequences', 'reads'],
// ... see defaultConfig for all options
}}
/>
`Data Structure
$3
The data should match the HIVDB GraphQL API response structure:
`typescript
interface AnalysisData {
currentVersion?: {
text: string;
publishDate: string;
};
currentProgramVersion?: {
text: string;
publishDate: string;
};
sequenceAnalysis: Array<{
inputSequence: {
header: string;
};
strain: {
name: string;
display: string;
};
availableGenes: Array<{ name: string }>;
bestMatchingSubtype: {
display: string;
referenceAccession: string;
};
subtypes: Array<{
displayWithoutDistance: string;
distancePcnt: string;
referenceAccession: string;
referenceCountry: string;
referenceYear: number;
}>;
validationResults: Array<{
level: string;
message: string;
}>;
alignedGeneSequences: Array<{
gene: { name: string };
firstAA: number;
lastAA: number;
mutations: Array<{
text: string;
position: number;
primaryType: string;
}>;
}>;
drugResistance: Array<{
gene: { name: string };
drugScores: Array<{
drug: { name: string; displayAbbr: string };
score: number;
level: number;
text: string;
partialScores: Array<{
mutations: Array<{ text: string }>;
score: number;
}>;
}>;
}>;
}>;
mutationPrevalenceSubtypes?: Array<{
name: string;
stats: object;
}>;
}
`Exports
`jsx
import {
HIVDBReport, // Main report component
defaultConfig // Default configuration object
} from '@basic-genomics/hivdb-report';
`API Integration
$3
When using
enableSequenceInput={true}:1. User enters sequence(s) in FASTA format
2. User selects output format (HTML Report / CSV/JSON)
3. Component calls
onFetchReport or onFetchExport with sequence text
4. A simulated progress bar is displayed during the request
5. API response is validated for required fields
6. Results are displayed or downloaded$3
The component provides built-in error handling:
- Input validation: Empty sequences are rejected
- API errors: Network failures and HTTP errors are caught
- Data validation: API responses are validated for required fields
- User feedback: Clear error messages are displayed
$3
When implementing API integration with
onFetchReport/onFetchExport:`jsx
// ✅ Good: Use environment variables for sensitive data
const handleFetchReport = async (sequenceText) => {
const response = await fetch(process.env.REACT_APP_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${process.env.REACT_APP_API_TOKEN}
},
body: JSON.stringify({ sequences: sequenceText })
});
return response.json();
};// ❌ Bad: Never hardcode tokens
const handleFetchReport = async (sequenceText) => {
const response = await fetch('https://api.example.com', {
headers: {
'Authorization': 'Bearer hardcoded-token-123' // Don't do this!
},
// ...
});
};
`Styling
The component includes all necessary styles automatically. No additional style imports are needed.
> Note: If you encounter style issues, ensure your build system supports SCSS. The component uses SCSS for styling internally.
Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
TypeScript Support
While the component is written in JavaScript, TypeScript definitions are provided for better IDE support:
`typescript
import { HIVDBReport, AnalysisData } from '@basic-genomics/hivdb-report';// Sequence Input Mode
const MyComponent: React.FC = () => {
const handleFetchReport = async (sequenceText: string): Promise => {
const result = await api.analyze(parseSequences(sequenceText));
return result;
};
return (
enableSequenceInput={true}
onFetchReport={handleFetchReport}
/>
);
};
// Direct Data Mode
const DirectDataComponent: React.FC<{ data: AnalysisData }> = ({ data }) => {
return ;
};
`Development
`bash
Install dependencies
yarn installStart development server (runs on port 3009)
yarn startBuild for production
yarn buildRun tests
yarn test
`Troubleshooting
$3
Q: Styles are not loading correctly
A: Ensure your build system supports SCSS. If using Create React App, this is supported by default. For custom webpack configs, install
sass-loader and node-sass.Q: API requests are failing with CORS errors
A: Configure CORS on your API server to allow requests from your application's origin. Add appropriate CORS headers:
`
Access-Control-Allow-Origin: https://your-app.com
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
`Q: Component shows "No valid sequence analysis data returned from API"
A: Ensure your
onFetchReport/onFetchExport function returns data with a sequenceAnalysis array containing at least one element.Q: Export (CSV/JSON) option is disabled
A: In Direct Data Mode, provide
exportData or ensure analysisData.allGenes exists. In Sequence Input Mode, provide onFetchExport function.Performance Considerations
- Data optimization: Use separate
reportData and exportData` to minimize initial loadMIT © Basic Genomics
- Stanford HIVDB - HIV Drug Resistance Database
- HIVDB GraphQL API - Data source API
- React - JavaScript library for building user interfaces
---
Made with ❤️ by Basic Genomics