@zomako/elearning-layout-engine
v1.1.3
Published
A lightweight, responsive, and SCORM-compliant HTML/CSS/JS foundation for eLearning courses
Downloads
219
Maintainers
Readme
eLearning Layout Engine
A lightweight, responsive, and SCORM-compliant HTML/CSS/JS foundation for eLearning courses.
Features
- Semantic HTML5: Proper HTML elements for accessibility and SEO
- Responsive Design: Works seamlessly on mobile, tablet, and desktop
- SCORM Compliant: Full integration with Learning Management Systems
- Pure CSS Animations: GPU-accelerated transitions without JavaScript overhead
- Slot-Based Components: Flexible injection of content and interactive components
- WCAG 2.1 AA Accessible: Built with accessibility first from the ground up
- Production-Ready: Tested and optimized for real-world eLearning deployment
Installation
npm install @zomako/elearning-layout-engineQuick Start
1. Build the library
cd node_modules/@zomako/elearning-layout-engine
npm run build2. Include in your course
Create an HTML file that references the built assets:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Course</title>
<link rel="stylesheet" href="path/to/elearning-layout-engine/dist/css/main.css">
<link rel="stylesheet" href="path/to/elearning-layout-engine/dist/css/elearning-components.css">
<link rel="stylesheet" href="path/to/elearning-layout-engine/dist/css/component-overrides.css">
</head>
<body>
<div class="viewport">
<div class="slides">
<!-- Add your slides here -->
</div>
</div>
<script src="path/to/elearning-layout-engine/dist/js/react.production.min.js"></script>
<script src="path/to/elearning-layout-engine/dist/js/react-dom.production.min.js"></script>
<script src="path/to/elearning-layout-engine/dist/js/elearning-components.umd.js"></script>
<script src="path/to/elearning-layout-engine/dist/js/scorm.js"></script>
<script src="path/to/elearning-layout-engine/dist/js/main.js"></script>
</body>
</html>3. Add slides
Insert slides with the .slide class into .slides:
<section class="slide" data-slide-id="slide-1" data-slide-type="content">
<header class="slide__header">
<h1>Welcome to the Course</h1>
</header>
<main class="slide__body">
<p>This is the first slide content.</p>
</main>
<footer class="slide__footer">
<button onclick="slideManager.nextSlide()">Next</button>
</footer>
</section>Project Structure
elearning-layout-engine/
├── dist/ # Build output (generated by npm run build)
│ ├── css/
│ │ └── main.css
│ ├── js/
│ │ ├── main.js
│ │ └── scorm.js
│ ├── templates/
│ │ ├── slide.html # Master template
│ │ ├── content-slide.html
│ │ ├── accordion-slide.html
│ │ ├── dnd-slide.html
│ │ ├── timeline-slide.html
│ │ ├── matching-slide.html
│ │ ├── sorting-slide.html
│ │ ├── quiz-slide.html
│ │ └── branching-slide.html
│ └── index.html
├── src/
│ ├── css/
│ │ └── main.css
│ ├── js/
│ │ ├── main.js
│ │ └── scorm.js
│ ├── templates/
│ └── index.html
├── package.json
└── README.mdSlide Structure
Each slide follows this structure:
| Element | Class | Description |
|---------|-------|-------------|
| Header | .slide__header | Title and metadata |
| Body | .slide__body | Main content (text, media, lists) |
| Footer | .slide__footer | Navigation, interaction area |
| Interaction Area | .slide__interaction-area | Mount point for interactive components |
Data Attributes
data-slide-id– Unique identifier for SCORM lesson locationdata-slide-type–content|interaction|assessmentdata-interaction-type– Type of interaction (see below)data-config– JSON string with component props (for integrated components)
Integrated Components (@zomako/elearning-components)
The layout engine automatically mounts components from @zomako/elearning-components when present. Supported data-interaction-type values:
| Type | Component | Config via data-config |
|------|-----------|--------------------------|
| accordion | Accordion | {"items":[{"id","title","content"}],"allowMultiple","defaultOpenId"} |
| dnd, drag-and-drop | DragAndDropActivity | Component-specific props |
| timeline | InteractiveTimeline | Component-specific props |
| matching | MatchingActivity | Component-specific props |
| sorting | SortingActivity | Component-specific props |
| flashcard, quiz | FlashcardDeck | {"cards":[{"front","back"}]} |
| branching | BranchingScenario | Component-specific props |
Adaptive Sizing
The layout engine automatically gives interactive components balanced screen space. When a slide has a .slide__interaction-area with data-interaction-type, the interaction area:
- Uses ~28% of viewport height (min 120px, max 350px) on desktop—kept compact to limit scrolling when content expands
- Gets a proportional share of the slide grid
- Scales text for readability without dominating the viewport
- Adapts on mobile (~24% viewport height) for smaller screens
No extra configuration needed—it activates when data-interaction-type is present.
Component Overrides
component-overrides.css (loaded after elearning-components.css) ensures:
- Accordion and BranchingScenario components fill the full width of the interaction area (overriding their default max-width)
- Choice buttons are more compact to reduce vertical scroll
Example with Accordion:
<div class="slide__interaction-area"
data-interaction-type="accordion"
data-config='{"items":[{"id":"1","title":"Section 1","content":"Content here"}],"allowMultiple":true}'>
</div>API Reference
SlideManager (global: window.slideManager)
| Method | Description |
|--------|-------------|
| showSlide(index) | Show slide by index (0-based) |
| nextSlide() | Go to next slide |
| previousSlide() | Go to previous slide |
| goToSlide(slideId) | Jump to slide by data-slide-id |
| getCurrentSlide() | Get the active slide element |
| getTotalSlides() | Get total slide count |
SCORM (global: scorm)
| Method | Description |
|--------|-------------|
| init() | Initialize connection to LMS (auto-called on load) |
| finish() | Terminate LMS connection |
| get(param) | Get value from SCORM data model |
| set(param, value) | Set value in SCORM data model |
| commit() | Persist data to LMS |
| setStatus(status) | Set lesson status (e.g., "completed") |
| setScore(score, maxScore) | Set and commit score |
| setLocation(location) | Set current slide ID |
| getStatus() | Get lesson status |
| getScore() | Get raw score |
| getLocation() | Get lesson location |
| isInitialized() | Check if SCORM is connected |
Custom Events
mountInteraction
Dispatched when a slide with an interaction area becomes active. Listen to mount custom components:
document.addEventListener('mountInteraction', (e) => {
const { slideId, interactionType, container } = e.detail;
// Build and inject your interaction into container
});interactionCompleted
Dispatch when an interaction is complete to update SCORM score:
document.dispatchEvent(new CustomEvent('interactionCompleted', {
detail: {
slideId: 'quiz-1',
score: 8,
maxScore: 10
}
}));Templates
The master template (slide.html) uses placeholders:
{{slideId}}– Unique slide identifier{{slideType}}– content | interaction | assessment{{title}}– Slide title{{content}}– Slide body content{{interactionType}}– Interaction component type
Specialized templates extend this for accordion, quiz, drag-and-drop, matching, sorting, timeline, and branching slides.
SCORM Compliance
The library uses the SCORM 1.2 data model:
cmi.core.lesson_status– Lesson statuscmi.core.lesson_location– Current slide IDcmi.core.score.raw– Raw scorecmi.core.score.max– Maximum score
When no LMS is present, the library runs in standalone mode with console logging.
Accessibility
- Keyboard navigation – Arrow keys (← →) for slide navigation
- Focus styles – Visible focus outline on buttons and links
- Reduced motion – Respects
prefers-reduced-motionmedia query - High contrast – Respects
prefers-contrastfor stronger borders - Skip link – Add
.skip-linkfor keyboard users to skip to main content
Testing
A test.html file is included for local verification. After building:
npm run build
npx serve .Then open http://localhost:3000/test.html in your browser. The test includes sample Accordion and Flashcard slides.
Browser Support
Modern browsers (Chrome, Firefox, Safari, Edge). Uses 100dvh for viewport height—fallback may be needed for older browsers.
License
MIT
