The first thing this course does is delete fifty lines of working code.

They are the plain query surface the engine course ends on — a textarea, a button, a table built by hand — and they work fine. Deleting them is the point. What replaces them is an architecture: state that lives in one place, a query layer that cannot race itself, and twelve components that subscribe to data by reading it.

The database underneath does not change. Not one line of the worker, the contract, or the query functions is edited in these eleven lessons. That constraint is what makes the course honest about where the difficulty actually is — it is never in the SQL.

The interface you’ll ship

An analytics dashboard with no backend: filter by date with a dual-handle slider, pick items from a popover that gets light dismiss and Escape from the platform, click a bar to cross-filter, page through twenty thousand rows, flip the table to a month-by-item pivot, run your own SQL, watch per-query round-trips in a performance panel, and drag one slider to recolor the entire application in both light and dark.

Every panel can also show you the SQL behind it, because the engine course built that in.

Architecture diagram: user actions write to a signals store, a debounced watcher runs five queries in parallel and lands only the newest result, and twelve Lit components re-render by reading the same store

Eleven lessons, eleven tags

Tags ui-01 through ui-11 in the companion repository. Consecutive tags diff to exactly one lesson’s work.

  1. The store is a module — signals as truth, computeds as views, actions as the only way in.
  2. A debounced, race-free query runner — eight rapid clicks, one query, and a request id that makes a slow answer impossible to see.
  3. First components, and the scaffolding dies — registration at import time, @lit/task, and the deletion the course opened with.
  4. Stat cards and sparklines — one element parameterized three ways.
  5. Filters on platform primitives — the Popover API deletes more code than it adds.
  6. The dual-handle slider — two range inputs behaving as one control, and a reset button revealed by :has() alone.
  7. D3 inside a shadow root — selecting renderRoot, and a chart that is an input as well as an output.
  8. The heatmap D3 didn’t build — a hundred and eighty cells of CSS grid and color-mix(), with no SVG at all.
  9. The table — sorting, pagination, a pivot view, and the accessibility work a table actually needs.
  10. The app explains itself — a SQL console, verbatim engine errors, and a live performance readout.
  11. What “wow” costs, as one diff — the entire design system in a single commit you can read.

The two lessons that argue with each other

Lesson 7 builds two D3 charts. Lesson 8 builds a calendar heatmap with no charting library at all — seven rows of CSS grid, one column per week, and a custom property per cell fed into color-mix(). It renders a hundred and eighty cells and contains zero SVG elements.

Putting them back to back is deliberate. D3 earns its place when you need scales, axes, and interpolated transitions; it is dead weight when you need a grid of colored squares. Most component libraries never make that distinction, and most dashboards are heavier than they need to be because of it.

Reading it without writing it

Every lesson ends with a Build it table, one objective Done when check, and an answer-key diff. If you would rather read than type, the diffs are the course — each one is between two and nine files, sized to be read in a sitting.

Nothing here is generated. Every component was verified running in a real browser at the tag it lands on.

Who ends up glad they took it

Developers who have been told web components are not ready and would like to check. React engineers curious what a signals store looks like when it is not bolted onto a render loop. Anyone who has built a dashboard where dragging a filter fires a request per pixel, and wants the version that fires one.

Where it goes next

Testing the Untestable covers the test suite this codebase deliberately ships without — real browsers, real wasm, real workers, deterministic seeding, and the fake-timer tests that pin down the query runner’s debounce and staleness guarantees. Seven lessons, $5.