# CleanLit Framework — Comprehensive Guide
**CleanLit** is a revolutionary, ultra-lightweight frontend architecture designed for the modern web. It represents the dawn of a new era in web development—stripping away the complexity of build tools to deliver pure, unadulterated performance and developer joy.
---
## Core Philosophy
- **Zero-Build Architecture**: Harnesses the raw power of native ES Modules (`import`/`export`) directly in the browser. No Webpack. No Vite. No Parcel. No waiting for builds.
- **Native Web Components**: Built on the elegant [Lit](https://lit.dev/) library (~5KB gzipped) as the recommended default, while staying compatible with any standards-based web component helper.
- **Hybrid MPA/SPA Experience**: Combines the SEO and simplicity of Multi-Page Applications with the rich, fluid interactivity of Single Page Apps.
- **Encapsulated Brilliance**: Leverages Shadow DOM for bulletproof style isolation while offering a powerful global theming engine.
- **Containerized Pages**: Treats every page as a self-contained unit (like a Docker container), ensuring total isolation and portability.
---
## Why CleanLit? (The Four Pillars)
### A. AI-First Framework
CleanLit is designed from the ground up to be **LLM-friendly**:
- **Compartmentalized Architecture**: Each page is a self-contained folder. LLMs can read, understand, and modify a single page without needing context from the entire codebase.
- **Small, Focused Files**: Components are typically 50-200 lines. No massive monolithic files that exceed context windows.
- **Predictable Patterns**: Every component follows the same 6-step structure (import → class → styles → render → logic → register). LLMs can generate new components reliably.
- **No Build Artifacts**: What you see is what runs. No transpiled code, no source maps to decode, no hidden complexity.
- **Easily Extendable**: Adding a new page or component is as simple as creating a new folder and following the pattern. No configuration files to update, no build system to appease.
### B. Human-First Framework
CleanLit prioritizes **developer experience and cognitive clarity**:
- **Easy to Reason About**: Open any page folder and instantly see everything that makes it work. No mental gymnastics tracing imports across dozens of directories.
- **Standalone Pages**: Each page is independent. You can understand, debug, or delete a page without understanding the entire application.
- **Scales to Large Products**: The containerized pattern doesn't limit you. Use `shared/components` for truly reusable pieces, and build applications with hundreds of pages while maintaining clarity.
- **Fast Onboarding**: New team members (human or AI) can be productive in minutes, not days. The architecture is self-documenting.
- **No Framework Lock-in**: Built on web standards (ES Modules, Web Components, CSS Variables). Your knowledge transfers everywhere.
### C. Massive Time Savings
CleanLit eliminates entire categories of time waste:
- **No Build Steps**: Save a file, refresh the browser. Changes appear in <100ms. No waiting for webpack, no HMR glitches, no "rebuilding..." spinners.
- **No Dependencies to Install**: Clone the repo and start working. No `npm install` that takes minutes and downloads gigabytes.
- **No Dependencies to Maintain**: No Dependabot alerts. No breaking changes from transitive dependencies. No "npm audit" vulnerabilities to chase.
- **No Configuration Files**: No `webpack.config.js`, no `babel.config.js`, no `tsconfig.json`, no `.babelrc`. Just HTML, CSS, and JavaScript.
- **No Build Tool Debugging**: Never again spend hours debugging why your build is broken. There is no build.
### D. Security by Design
CleanLit's zero-dependency approach provides **inherent security**:
- **No Supply Chain Attacks**: With no `node_modules`, there's no attack surface for malicious packages. You can't be compromised by a dependency you don't have.
- **No Transitive Dependencies**: Traditional projects have hundreds of hidden dependencies. Each one is a potential vulnerability. CleanLit recommends Lit from CDN as a lightweight helper, but you can choose any standards-based alternative—nothing ships bundled.
- **Auditable Codebase**: Every line of code that runs is visible in your repository. No minified bundles hiding malicious code.
- **CDN Integrity**: Lit (or your chosen helper) is loaded from a versioned CDN URL with subresource integrity. You control exactly what code runs.
- **Reduced Attack Surface**: Fewer moving parts = fewer things that can go wrong = fewer security vulnerabilities.
---
## Zero-Build Architecture (In Depth)
The web platform is your build tool. Just write modern JavaScript, import your components, and refresh your browser.
### Why Zero-Build Matters
| Benefit | Description |
|---------|-------------|
| **Instant Feedback Loop** | Save and refresh. Changes appear in <100ms, not seconds. No HMR lag, no watching build processes spin. |
| **SEO Friendly by Default** | Every page is a real HTML file with proper semantic structure. Search engines see exactly what users see—no client-side rendering tricks. |
| **Zero Dependency Hell** | No `node_modules` folder consuming gigabytes. No supply chain vulnerabilities. No breaking changes from 500 transitive dependencies. CleanLit recommends Lit from CDN by default, but any standards-based helper works. |
| **Saves Computing Resources** | Your CPU stays cool. No webpack churning through thousands of files. Your laptop battery thanks you. |
| **Trivial Debugging** | Browser DevTools show your actual source code, not transpiled/minified bundles. Stack traces are readable. Line numbers match your editor. No source maps needed—what you write is what runs. |
| **Future-Proof Longevity** | Built on web standards, not framework churn. Your code works today and will work in 10 years because ES Modules are part of JavaScript itself. No framework migrations. No rewrites required. |
---
## Web Components with Lit
Web Components are **native browser APIs** that let you create reusable, encapsulated custom HTML elements. No framework lock-in. No proprietary abstractions.
CleanLit uses **Lit**—a lightweight library that supercharges Web Components with reactivity, templating, and an elegant developer experience. Lit is our recommended starter for ergonomics, but the architecture works with plain Custom Elements or other standards-based helpers like FAST’s element base classes, Hybrids, or Haunted.
### Why Lit?
- **~5KB gzipped** — all the power of modern frameworks without the bloat
- **W3C Standard** — built on native Web Components spec
- **Universal Browser Support** — works everywhere
- **Framework Agnostic** — use alongside any other library
### Other options that work well
- **Plain Custom Elements** — for absolute minimalism
- **FAST Element base classes** — if you want Microsoft’s design system primitives
- **Hybrids / Haunted** — lightweight functional takes on Web Components
### Anatomy of a Component (6 Steps)
Every Lit component follows a simple, predictable structure:
```javascript
// 1. Import Lit from CDN (no npm install!)
import { LitElement, html, css } from 'https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js';
// 2. Define your component class
export class MyButton extends LitElement {
// 3. Define encapsulated styles (Shadow DOM) — scoped to this component
static styles = css`
button {
background: var(--clr-primary);
color: white;
padding: 1rem 2rem;
border: none;
border-radius: 0.5rem;
cursor: pointer;
}
`;
// 4. Define the component's template — what gets rendered
render() {
return html`
`;
}
// 5. Define event handlers & methods
handleClick() {
alert('Button clicked!');
}
}
// 6. Register the custom element — use as
customElements.define('my-button', MyButton);
```
**Breakdown:**
1. **Import** — Import Lit directly from CDN. The browser fetches it once and caches it.
2. **Class** — Extend `LitElement` to inherit reactive properties, lifecycle methods, and rendering capabilities.
3. **Styles** — CSS in JavaScript using tagged template literals. Styles are automatically scoped via Shadow DOM.
4. **Template** — The `render()` method returns HTML using the `html` tagged template. It's reactive—updates automatically when properties change.
5. **Logic** — Standard JavaScript methods for handling events, fetching data, or any other logic.
6. **Registration** — Register with a custom tag name (must contain a hyphen). Now use it anywhere: ``
---
## Page-Centric Architecture
CleanLit champions a **Self-Contained Page Pattern**, treating each page like a **Docker container**. Each page resides in its own directory, encapsulating all its specific assets, components, and styles.
### The Docker Analogy
Just like a Docker container packages an application with all its dependencies:
- **Isolation**: Each page is independent, with its own components and styles
- **Portability**: Move a page folder anywhere and it just works
- **Clarity**: All dependencies visible in one place
- **No Conflicts**: Two pages can have components with the same name without issues
### Page Directory Structure
A self-contained page has everything it needs in one folder:
```text
/dashboard/
├── index.html # The entry point (route)
├── dashboard.css # Page-specific global styles (optional)
├── stats-card.js # Local component
├── chart-widget.js # Local component
└── user-summary.js # Local component
```
### How It All Connects
```html
```
### Key Principles
- **Colocation**: Components live next to the page that uses them. No hunting through a massive `/components` folder.
- **Single Responsibility**: Each page folder has one job: render that specific route.
- **Easy Refactoring**: Delete a page? Delete its folder. Move a page? Move its folder. No dependency tracking needed.
- **Team-Friendly**: Multiple developers can work on different pages without merge conflicts.
### Why This Matters
| Benefit | Description |
|---------|-------------|
| **Lower Cognitive Load** | Open a page folder and immediately see everything that makes it work. No mental gymnastics tracing imports across 5 directories. |
| **Faster Onboarding** | New team members understand the codebase in minutes, not days. Each page folder is self-documenting. |
| **True Isolation** | Components in one page can't accidentally break another page. Delete a feature? Delete its folder. Zero ripple effects. |
| **Scales Infinitely** | 10 pages or 1000 pages, the mental model stays the same. Complexity grows linearly, not exponentially. |
| **Encourages Reuse When It Matters** | You still have `/shared/components` for truly reusable parts. But you're not forced to make everything "reusable" prematurely. Start local, promote to shared when needed. |
---
## Compositional Shell Pattern & AppLayout
CleanLit recommends a **Compositional Shell Pattern**. Instead of a monolithic SPA, simple HTML pages hydrate a reusable shell component that provides structure and chrome.
### `` — The Universal Shell
`` is the recommended universal shell. While optional, using this wrapper provides a consistent, responsive, and adaptive viewport.
**Composition:**
- **Header**: Renders `` for navigation and identity management
- **Body**: Uses a standard Web Component `` to inject page-specific content
- **Footer**: Renders `` for site-wide links and copyright info
- **Responsibility**: Global grid management, responsive scaling, and slot projection
### How to Use AppLayout (3 Steps)
**Step 1: Import AppLayout**
```html
```
**Step 2: Wrap Your Content**
```html
```
**Step 3: That's It!**
AppLayout automatically renders the navbar at the top, your content in the middle (via slot), and the footer at the bottom. No configuration needed.
### Under the Hood
```javascript
import { LitElement, html, css } from 'https://cdn.jsdelivr.net/gh/lit/dist@3/...';
import './app-navbar.js';
import './app-footer.js';
export class AppLayout extends LitElement {
static styles = css`
:host {
display: flex;
flex-direction: column;
min-height: 100vh; /* Full viewport height */
background-color: var(--clr-surface);
}
main {
flex: 1; /* Grow to fill space */
width: 100%;
}
`;
render() {
return html`
`;
}
}
customElements.define('app-layout', AppLayout);
```
**Key Insights:**
- **Flex Layout**: Uses flexbox to ensure footer sticks to bottom even on short pages
- **Slot Pattern**: The `` element projects your page content into the layout
- **Composition**: AppLayout imports and composes navbar + footer automatically
- **Minimal Code**: Just ~30 lines of code for the entire application shell!
### `` — The Intelligent Navigator
- **Context Aware**: Adapts instantly to user session state
- **Theme Engine**: Seamless Light/Dark mode switching
- **Adaptive Layout**: Morphs from desktop navigation to mobile touch interfaces
---
## Directory Model & Zones
CleanLit promotes a clean separation of concerns, distinguishing between the reusable framework core and the application implementation.
| Directory | Purpose |
|-----------|---------|
| `shared/components` | **CleanLit Core**. The reusable building blocks (Layouts, Navbars, UI Kit). |
| `shared/styles` | **Design System**. The visual language—variables, typography, and utility classes. |
| `public` | **Public Zone**. High-performance landing pages and marketing content. |
| `app` | **Application Zone**. Rich, interactive dashboards and functional tools. |
| `auth` | **Identity Zone**. Secure login, registration, and profile flows. |
The **idea** is consistent:
- A small **shared core** that multiple pages import
- Multiple **isolated page containers** that own their local components
---
## Theming & Design System
CleanLit features a **Dynamic CSS Variable Engine**, enabling real-time, high-performance theme switching without page reloads or heavy JavaScript overhead.
### How Theme Switching Works
1. User toggles theme (e.g., clicks button in navbar)
2. Navbar switches internal state (Light ↔ Dark)
3. Navbar persists preference to localStorage
4. Navbar injects new token values to document root
5. Browser repaints (hardware accelerated)
### Default Palette (Customizable)
| Token | Value | Description |
|-------|-------|-------------|
| `--clr-primary` | `#A33332` | Crimson — primary brand color |
| `--clr-surface` | `#F8F5F1` | Cream — main background |
| `--clr-ink` | `#1A3C34` | Deep Green — text/code backgrounds |
### Available Design Tokens
**Colors:**
- `--clr-primary` — Primary brand color
- `--clr-surface` — Main background surface
- `--clr-bg-alt` — Alternate/zebra background
- `--clr-text-main` — Primary text color (dynamic with theme)
- `--clr-text-muted` — Secondary/muted text
- `--clr-text-on-primary` — Text on primary color backgrounds
**Spacing Scale:**
- `--spacing-xs` → `0.25rem`
- `--spacing-sm` → `0.5rem`
- `--spacing-md` → `1rem`
- `--spacing-lg` → `2rem`
- `--spacing-xl` → `4rem`
**Glass Effects (Glassmorphism):**
- `--glass-surface` — `rgba(255,255,255,0.85)` with backdrop blur
- `--glass-border` — `rgba(163,51,50,0.15)`
**Shadows:**
- `--shadow-sm`, `--shadow-md`, `--shadow-lg`
### Characteristics
- **Instant theme switches**: No reloads; the browser repaints using new variable values
- **Shadow DOM friendly**: Components read from the same variable names, so themes apply everywhere
- **Customizable palettes**: Override tokens per brand or deployment
**Pro Tip:** CSS variables automatically update with theme changes. Use them everywhere and dark mode comes for free!
---
## Authentication Flow
Security is baked into the core. The Navbar component acts as a **Client-Side Sentinel**, managing UI state based on session validity.
**Flow:**
1. **Guest State**: Validate session → No session → Show Login
2. **Login Success**: Transition to Authenticated state
3. **Authenticated State**: Show Dashboard, Show User Controls
4. **Logout Action**: Return to Guest state
The Sentinel checks storage & API, then updates UI state reactively.
---
## Testing Philosophy (with Deno)
Just as CleanLit eliminates build complexity from your frontend, **testing should be simple, fast, and dependency-free**. No `package.json`, no test runners to configure, no build step before running tests.
### Why Deno for CleanLit?
| CleanLit Principle | Deno Advantage |
|-------------------|----------------|
| **Zero-Build Architecture** | No build step required—runs ES modules natively |
| **Native ES Modules** | First-class ESM support matches CleanLit's import philosophy |
| **Minimal Dependencies** | Built-in test runner, assertions, and utilities |
| **CDN-Friendly** | Can import from URLs just like browsers |
| **Single Executable** | Perfect for LLMs and CI—no npm install overhead |
| **TypeScript Optional** | Can gradually add `.ts` without breaking `.js` workflow |
| **CLI-First** | Designed for automation and developer productivity |
### Test Structure
CleanLit organizes tests by **responsibility**, mirroring the framework's modular architecture:
```text
tests/
├── components/ # Web Component unit tests
│ ├── navbar_test.js
│ ├── layout_test.js
│ └── footer_test.js
├── pages/ # Page integration tests
│ ├── home_test.js
│ └── learn_test.js
├── themes/ # Theme system tests
│ ├── tokens_test.js
│ └── dark_mode_test.js
├── integration/ # End-to-end workflows
│ ├── navigation_test.js
│ └── routing_test.js
└── architecture/ # Architecture validation
├── imports_test.js
├── isolation_test.js
└── performance_test.js
```
### Test Categories
**Component Tests** — Test individual Web Components for:
- Valid ES module exports
- Correct custom element registration
- LitElement lifecycle methods
- Reactive properties
- Shadow DOM styles
**Page Tests** — Test entire pages for:
- CleanLit containerized pattern compliance
- SEO essentials (title, meta tags)
- Proper component imports
- No bundler artifacts
- Semantic HTML structure
**Theme Tests** — Test the theming system for:
- CSS token definitions
- Dark mode support
- Consistent color palette
**Integration Tests** — Test cross-page workflows:
- Navigation links validity
- Shared component consistency
- Theme persistence
**Architecture Tests** — Validate CleanLit principles:
- No heavy framework dependencies
- Relative or CDN imports only
- Component isolation
### Example Test
```javascript
import { assertEquals } from "https://deno.land/std@0.224.0/assert/mod.ts";
Deno.test("app-navbar exports a valid Lit component", async () => {
const code = await Deno.readTextFile("./shared/components/app-navbar.js");
assertEquals(code.includes("export class"), true, "Should export a class");
assertEquals(code.includes("LitElement"), true, "Should extend LitElement");
assertEquals(code.includes("customElements.define"), true, "Should register element");
});
```
### Running Tests
```bash
# Run all tests
deno test --allow-read
# Run specific category
deno test --allow-read tests/components/
# Watch mode
deno test --allow-read --watch
```
---
## Development Best Practices (7 Guidelines)
### 1. Always Extend LitElement
Every component should inherit from `LitElement` to get reactive properties, efficient rendering, and lifecycle hooks.
```javascript
// ✅ Good
import { LitElement, html, css } from 'https://...';
export class MyComponent extends LitElement {
static styles = css`...`;
render() { return html`...`; }
}
// ❌ Bad: Plain HTMLElement loses Lit's features
class MyComponent extends HTMLElement { ... }
```
### 2. Use CSS Variables for All Styling
Never hardcode colors, spacing, or typography. Always use design tokens from `theme.css`.
```javascript
// ✅ Good: Uses design tokens
css`
button {
background: var(--clr-primary);
padding: var(--spacing-md);
color: var(--clr-text-on-primary);
}
`
// ❌ Bad: Hardcoded values break theming
css`
button {
background: #A33332;
padding: 1rem;
color: white;
}
`
```
### 3. Keep Styles Encapsulated in Shadow DOM
Define component styles using the `static styles` property. Shadow DOM isolation means your styles won't leak, and global styles won't interfere.
```javascript
// ✅ Good: Encapsulated styles
static styles = css`
:host { display: block; }
.card {
background: var(--glass-surface);
padding: 2rem;
}
`;
```
### 4. Use Relative Imports
Import dependencies using relative paths. This keeps your components portable and makes the dependency graph explicit.
```javascript
// ✅ Good: Clear relative paths
import '../shared/components/app-layout.js';
import './my-local-component.js';
```
### 5. Name Components with Hyphens
Custom element names **MUST** contain a hyphen (Web Components spec requirement). Use kebab-case for consistency.
```javascript
// ✅ Good
customElements.define('my-button', MyButton);
customElements.define('user-profile', UserProfile);
// ❌ Bad: No hyphen (will throw error)
customElements.define('button', MyButton);
```
### 6. Clean Up in disconnectedCallback
If you add event listeners, timers, or subscriptions in `connectedCallback()`, remove them in `disconnectedCallback()` to prevent memory leaks.
```javascript
// ✅ Good: Proper cleanup
connectedCallback() {
super.connectedCallback();
window.addEventListener('resize', this.handleResize);
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener('resize', this.handleResize);
}
```
### 7. Prefer Composition Over Inheritance
Build complex UIs by composing simple components, not by creating deep inheritance hierarchies. Use slots to project content.
```html
My Title
Content goes here
```
---
## When CleanLit Shines
CleanLit is especially well-suited for:
- **Marketing sites and documentation** with rich, animated sections but minimal tooling
- **Dashboards and internal tools** that favor maintainable Web Components over framework lock-in
- **Projects where zero-build, native ESM, and low dependency overhead** are explicit goals
- **Teams that value fast onboarding** — the page-centric architecture is self-documenting
- **Long-lived projects** — built on web standards that won't require framework migrations
---
## Summary
By embracing:
- **Containerized pages** (Docker-like isolation)
- **A compositional shell** (`` with slots)
- **A token-driven design system** (CSS variables for instant theming)
- **Native ES modules** (zero build complexity)
- **Lit-based Web Components** (5KB, W3C standard, framework agnostic)
CleanLit delivers a modern, fast, and maintainable frontend architecture without the usual tooling complexity.
**The web platform is your build tool. Be Water. Be Light. Be Free.**