Technical Style Guide
This guide defines the technical standards, conventions, and deployment assumptions for the Literacy for Kids ecosystem.
Static-Site Architecture
Every site in the ecosystem is a static Docusaurus v3 site deployed to GitHub Pages. No server-side rendering, no database, no user accounts, no login, no analytics.
This is a deliberate choice:
- Zero infrastructure cost
- No student data to protect
- Anyone can fork and self-host
- GitHub Pages provides free, reliable hosting for open-source projects
Do not introduce server-side code, edge functions, or backend services without an explicit discussion.
Repository Layout
Hub (literacy_for_kids): Docusaurus at repo root
literacy_for_kids/
docs/ ← hub documentation (Markdown)
src/ ← React pages and components
static/ ← static assets (img/)
docusaurus.config.js
sidebars.js
package.json
.github/workflows/
Curriculum repos ({name}_literacy_for_kids): Docusaurus in /website
{curriculum}_literacy_for_kids/
website/
docs/ ← lesson content (Markdown)
src/ ← pages and components
static/ ← static assets
docusaurus.config.js
sidebars.js
package.json
.github/workflows/
README.md
LICENSE-CODE
LICENSE-CONTENT
Theme package (literacy_site_template): npm package only, no Docusaurus site
literacy_site_template/
src/
index.js ← Docusaurus plugin entry
css/custom.css ← shared CSS
data/ecosystemLinks.js ← single source of truth for all curriculum URLs
theme/ ← shared React components
package.json
GitHub Pages Deployment
URL pattern
Each site is served from its own custom (sub)domain:
https://{subdomain}.literacy-for-kids.com/
The hub uses https://www.literacy-for-kids.com/; each curriculum uses its topic
subdomain (e.g. https://computer.literacy-for-kids.com/).
Required Docusaurus config
url: 'https://{subdomain}.literacy-for-kids.com',
baseUrl: '/', // sites are served from the domain root
trailingSlash: true, // required for GitHub Pages static file routing
Why trailingSlash: true
GitHub Pages serves static files. Without trailing slashes, navigating to /docs/intro returns a 404 because GitHub Pages looks for docs/intro.html. With trailingSlash: true, Docusaurus generates docs/intro/index.html, which GitHub Pages serves correctly at /docs/intro/.
Deployment workflow
All sites deploy via GitHub Actions on push to main:
actions/configure-pages— initialize Pages environmentnpm ci— install from lockfilenpm run build— Docusaurus production buildnpm run validate:build(if present) — validate build outputactions/upload-pages-artifact(path:build/or./website/build/)actions/deploy-pages
GitHub Pages source must be set to GitHub Actions in repository Settings › Pages.
Base Path Rules
Every asset reference and internal link in the built output must use the base path. Docusaurus handles this automatically when baseUrl is set correctly. Do not hardcode paths.
Correct:
// In docusaurus.config.js
baseUrl: '/decision_literacy_for_kids/',
Incorrect:
baseUrl: '/', // root only — breaks project page deployment
baseUrl: '/docs/', // wrong path
baseUrl: '/decision-literacy/', // wrong separator
The validate:build script checks for root-relative paths that bypass the base path.
Package Manager
Use npm with a lockfile (package-lock.json). Do not use yarn or pnpm unless a repo already uses them.
In CI, always use:
npm ci # for curriculum repos
npm ci --legacy-peer-deps # for the hub (React 19 + Docusaurus peer dep constraint)
Node Version
Node 20 (LTS). Specified in:
package.jsonengines.node- GitHub Actions
actions/setup-nodewithnode-version: 20
Shared Theme Package
The literacy-site-theme package (from literacy_site_template) is the single source of truth for:
- All curriculum URLs and metadata (
src/data/ecosystemLinks.js) - Shared CSS custom properties (
src/css/custom.css) - Shared navigation and footer components
When adding a new curriculum: Update ecosystemLinks.js in literacy_site_template, bump the version, then update the literacy-site-theme dependency in every curriculum repo.
When a curriculum URL changes: Same process — update ecosystemLinks.js, bump version, update all repos.
Dependencies
Keep the dependency list minimal. The core dependencies are:
@docusaurus/coreand@docusaurus/preset-classic— the Docusaurus frameworkreactandreact-dom— Reactliteracy-site-theme— the shared theme package
Do not add:
- Analytics (Google Analytics, Plausible, etc.)
- Login or auth packages
- User data collection
- Heavyweight UI frameworks (Material UI, Tailwind, etc.) — use the existing Docusaurus Infima CSS
For tooling, keep linting/formatting lightweight. A .editorconfig file is sufficient for cross-editor consistency. Do not add ESLint or Prettier unless the repo already uses them.
Build Validation
Every repo should have npm run validate:build that checks the build output before deployment. See scripts/validate-build.mjs in the hub repo for the canonical implementation. Checks include:
- Build directory and
index.htmlexist - All referenced assets exist on disk
- No root-relative paths that bypass the base path
- No source-directory or localhost references
404.htmlexists for SPA fallback
Formatting and Style
.editorconfig applies across all repos:
- 2-space indentation for JS, JSON, YAML, Markdown
- LF line endings
- UTF-8 encoding
- Trim trailing whitespace
- Final newline
JavaScript files use ES modules (import/export) for Docusaurus site code. The shared theme package uses CommonJS (require/module.exports) for compatibility with the createRequire pattern in Docusaurus configs.
Accessibility Technical Requirements
- HTML root element must have
lang="en"(Docusaurus sets this automatically) - All images need alt text
- Interactive elements must be keyboard-accessible
- Navigation landmarks (
<nav>,<main>,<footer>) must be present (Docusaurus provides these via Layout) - Do not use
tabIndex > 0
See the Accessibility Notes doc for known issues.
What to Avoid
| Pattern | Why to avoid |
|---|---|
| Hardcoded absolute URLs in source | Breaks local development |
Root-relative paths (/docs/...) without base path | Breaks GitHub Pages project-page routing |
trailingSlash: false | Causes 404s on GitHub Pages |
Inline <script> tags loading external resources | Privacy and CSP concerns |
localStorage for user preferences that aren't cleared | Not needed; keep it simple |
fetch() calls to external APIs | Adds latency and external dependencies |
| Server-side rendering | Breaks static export |
gh-pages branch deployment | Use GitHub Actions deployment instead |