A lightweight, production-ready web application for searching and browsing training courses, labs, and certifications. Powered entirely by a CSV file — no backend database required.
- Instant search with 200ms debounce
- Relevance-ranked results with term highlighting
- Advanced filtering by status, product, technical level
- Sort by duration or publish date
- Expandable detail cards with all training metadata
- Dark mode support
- Responsive design (desktop, tablet, mobile)
- Keyboard navigation and screen reader support
- URL query parameters for shareable searches
- Embeddable via iframe
training-search-portal/
├── index.html # Main HTML page
├── styles.css # All styles (light + dark themes)
├── app.js # Application controller
├── csv-parser.js # CSV loading and parsing
├── search.js # Search engine, filtering, sorting
├── ui.js # UI rendering and interactions
├── utils.js # Utility functions
├── assets.csv # Training data (the database)
├── README.md # This file
└── assets/
├── icons/ # Custom icons (optional)
└── images/ # Custom images (optional)
- Clone or download the project.
- Serve the files using any web server:
# Python
python3 -m http.server 8000
# Node.js (npx, no install)
npx serve .
# PHP
php -S localhost:8000- Open
http://localhost:8000in your browser.
Upload all files to any standard web server. The application is fully static — no server-side runtime needed.
Copy the project files to your web root or a subdirectory. No special configuration required.
Push the repository to GitHub and enable Pages from Settings > Pages.
Upload all files to your bucket or CDN origin. Ensure assets.csv is served with Content-Type: text/csv or text/plain.
Replace assets.csv with your updated file. The application loads it fresh on each page visit.
- Encoding: UTF-8
- Delimiter: Comma (
,) - Header row: Required (first row)
- Quoting: Use double quotes (
") around fields that contain commas or newlines - Escaping: Use
""to represent a literal quote inside a quoted field
| Column | Description |
|---|---|
| ASSET TYPE | Type of training asset (e.g., Courses, Lab Plus) |
| SKU | Course SKU identifier |
| TITLE | Training title |
| DESCRIPTION | Training description (may contain HTML) |
| PFE DURATION | Duration (e.g., "4 hours 0 minutes", "5 Days") |
| PFE TECH LEVEL | Technical level (e.g., TL1, TL2, TL3) |
| PFE PRODUCT | Product name |
| INTERNAL STATUS | Status (Published, Retired, Under Development, In Planning) |
| INTERNAL PUBLISH DATE | Publication date |
| PTP URL | Partner training URL |
| INTERNAL COURSE URL | Primary internal course URL |
| COURSE URL | Secondary course URL |
| TRAINING URL | Tertiary training URL |
| RHLS CUSTOMER EXAM URL | Customer exam URL |
| PFE PRODUCT GROUP | Product group tag |
| Browser | Version |
|---|---|
| Chrome | Latest |
| Edge | Latest |
| Firefox | Latest |
| Safari | Latest |
<iframe
src="https://your-domain.com/training-search-portal/"
width="100%"
height="800"
style="border: none;"
title="Training Search Portal"
></iframe>For responsive height, use the iframe's onload event or a ResizeObserver.
| Key | Action |
|---|---|
/ |
Focus the search bar |
Esc |
Unfocus the search bar |
Enter / Space |
Expand/collapse a focused card |
Tab |
Navigate between elements |
Edit CSS custom properties in styles.css under :root to change colors, fonts, spacing, and border radius.
Edit search.js to modify:
- Searchable fields (
SEARCHABLE_FIELDS) - PERT asset type filter (
PERT_ASSET_TYPES) - Relevance scoring weights
Edit ui.js renderDetails() to add or remove fields from the expanded card view.
| Issue | Solution |
|---|---|
| Blank page | Ensure all JS files are in the same directory as index.html |
| "Unable to load" error | Verify assets.csv is in the same directory and the server is running |
| CORS error | Serve files via a web server, not by opening index.html directly |
| Garbled characters | Ensure assets.csv is saved as UTF-8 |
| No results | Check that the CSV has INTERNAL STATUS: Published rows with ASSET TYPE: Courses or Lab Plus |
Internal use only.