This is Part 3 of a three-part series. Part 1: why web components and Lit · Part 2: SSR, SSG, and CSR from one route table.

Talk is cheap. Parts 1 and 2 made claims; this post is the receipts.

lit-web-apps-examples is five working applications, each picked to kill a specific “but you need a framework for that” objection. All five were built by AI agents running lit-web-apps-skill, then verified end-to-end — strict TypeScript, real form participation, accessibility affordances, 74 tests. No demo shortcuts.

Here’s the tour, objection by objection.


1. lit-launch — “You need a framework for static sites with sprinkles”

SSG + lazy-hydrating islands. ~6 KB entry.

A marketing site with docs pages — the Astro/Next-static use case. Every page prerenders to Declarative Shadow DOM at build time; content paints and links navigate with zero JavaScript. The interactive bits are islands with chosen wake triggers: the theme toggle hydrates on browser idle, search hydrates on focus — and replays the keystroke that woke it, so the fast typist loses nothing.

This is the Part 2 islands story, running. Zero-JS-by-default isn’t a compromise; on content pages it’s simply correct.

2. lit-tasks — “You need React for rich interactivity”

CSR. 21 KB total, gzipped.

A kanban board: drag-and-drop across columns, FLIP animations when cards move, context menus, inline editing. The dependency list this app doesn’t have is the point — no framer-motion (FLIP is ~40 lines over getBoundingClientRect + View Transitions), no dnd-kit (a reusable pointer-capture drag controller), no portal library (Popover API puts menus in the top layer natively), no form library (form-associated custom elements via ElementInternals — the browser sees real form controls with real validation).

Four library categories, deleted. 21 KB is less than half of just React + ReactDOM, and it’s the whole app.

3. lit-pulse — “Fine, but it won’t scale”

CSR. ~28 KB total.

A real-time operations dashboard: a 50,000-row virtualized event log, canvas sparkline charts, and a signals store absorbing ~20 events per second. The hot path uses per-binding signal updates — watch() pins a signal directly to a text binding, so a metric tick updates that text node, not a component tree. No reconciliation, no memoization ceremony, no useCallback archaeology. The fast path is fast because there’s nothing in the way.

4. lit-shop — the flagship: “You need Next.js for a real product site”

Hybrid: SSG + SSR + CSR. ~71 KB raw, route-split.

The whole thesis in one app. A storefront where the one route table from Part 2 drives all three modes simultaneously: marketing pages prerendered at build time, product pages streaming server-side with per-page SEO metadata, cart and checkout client-rendered with localStorage persistence and a <dialog> checkout flow. XSS-safe __DATA__ serialization, tested. Deploy is npm run build && npm start — prerendered statics served, SSR streamed, one Node process, no adapter.

This is the “full Next.js replacement” claim, and it ships in less JavaScript than Next.js ships before your code.

5. lit-ui — “Components die with their framework”

SSR-safe design system.

Button, input, select, dialog, card — built on ElementInternals so they participate in native forms, themed with oklch + light-dark() design tokens, documented via Custom Elements Manifest. These components work in this repo’s apps, in a React app, in a Vue app, in server-rendered HTML, in whatever framework wins 2031. Write once; outlive your stack choices. (Sound familiar? It’s the whole Part 1 thesis, shipped as a library.)


The Crossover Episode: ecommerce-ui

There’s a sixth app, and it lives in a different repo — because it’s where two skills met.

In my Effect post I introduced effect-fp-skill-examples: a railway-oriented e-commerce backend in TypeScript. Its storefront — ecommerce-ui — was built with the lit-web-apps skill. One agent session, two skills composing:

  • The rendering split, chosen by content: catalog and product pages are SSR (crawlable, paint-without-JS, per-route titles); the auth-gated order history is CSR. One route table, one component set — the Part 2 architecture making real decisions.
  • The router is ~80 lines over URLPattern + the Navigation API, with view transitions on navigation. That line count is the argument.
  • The design system derives from a single oklch hue token through color-mix() — brand, hovers, surfaces, light and dark via light-dark(). (Regular readers will recognize the approach — this very blog works the same way.)

And the honest part — building it surfaced real sharp edges, which is the entire point of proving skills against real apps:

  • Lit SSR HTML-escapes bindings inside <script> — serialized JSON needs an audited unsafeHTML path
  • A shell’s firstUpdated fires while children are still hydrating; restore state too early and you corrupt it
  • @lit/task renders INITIAL on the server but PENDING on the client’s first pass — templates must treat them identically or hydration double-renders

Every finding was folded back into the skill. The skill builds the app; the app debugs the skill. That loop — not any single example — is why I trust these skills with real work.


Run Everything Yourself

Each app is standalone (Node ≥ 20):

git clone https://github.com/mikezupper/lit-web-apps-examples.git
cd lit-web-apps-examples/lit-shop   # or lit-launch, lit-tasks, lit-pulse, lit-ui
npm install
npm run dev

The whole test suite — Declarative Shadow DOM emission, SEO metadata, JSON escape safety, store immutability, virtualization math — runs in Node, no browser downloads:

for app in lit-launch lit-tasks lit-pulse lit-shop lit-ui; do
  (cd $app && npm test)
done
# 74 tests, under a second per suite

And the skill that built all of it:

git clone https://github.com/mikezupper/lit-web-apps-skill.git ~/.claude/skills/lit-web-apps

New Claude Code session → “build me a …” → it triggers automatically (or invoke /lit-web-apps). A SKILL.md plus 13 reference guides — components, templating, signals and state, rendering modes, routing, forms, testing, security — maintained as a dated snapshot with quarterly audits against the Lit release train. Codex and OpenCode read the same format (setup paths here).


Series Wrap

Three posts, one argument:

  1. The platform ships the component model now — custom elements, shadow DOM, and Declarative Shadow DOM ended the era where frameworks were mandatory. Lit is 5 KB of ergonomics on top, not a runtime you marry.
  2. Rendering strategy is a data structure, not a product — SSR, SSG, and CSR from one route table; hydration and islands are disciplines that fit in your head.
  3. Five apps prove it — and an agent skill means you don’t hold the discipline in your head anyway. You hold it in a repo.

The metaframework tax is optional. Stop paying it.

Star the repos if this series earned it — lit-web-apps-skill and lit-web-apps-examples — and follow me on X: @mikezupper. Next up: more skills, more apps stress-testing them, and everything that breaks along the way.

The platform outlived every framework. Bet accordingly.