Learn Frontend Engineering

How user intent becomes interactive, accessible, performant pixels. Thirty-five modules, from what the browser actually is to debugging a production frontend.

IntentEventStateUI LogicDOM WorkNetworkLayout / PaintPixelsFeedback

Browser Fundamentals

6 lessons

The browser is a runtime, not a document viewer: networking, parsers, a JavaScript engine, a layout engine, a paint system, a compositor, storage and a security sandbox, split across processes that fail independently.

The Browser Is a Runtime
▶ lab

Not a document viewer with scripting bolted on: a sandboxed application platform with a scheduler, a memory model, a renderer and a security boundary.

Q · What is actually executing my application, and what services does it provide?
What Happens When You Open a Website
▶ lab

URL to pixels: resolution, connection, request, streaming HTML, DOM and CSSOM, style, layout, paint, composite — and what blocks what.

Q · Between pressing Enter and seeing content, what exactly happens, and which step is the one holding me up?
The Multi-Process Browser

Browser, renderer, network, GPU and utility processes — why a page can hang without taking the browser with it, and what that means for your code.

Q · When my page freezes, what exactly is frozen, and what is still running?
The Frontend Reasoning Loop
▶ lab

Intent, event, state, logic, DOM, network, layout, paint, pixels, feedback — the chain every lesson in this domain is a zoom into.

Q · What is the general shape of every interaction, so I can ask the same questions of any feature?
Origins and the Sandbox

Scheme, host and port together form the unit of trust — and nearly every confusing browser restriction is that boundary being enforced.

Q · Why can my page not simply read that other page, that other API, or that file?
What the Frontend Is Responsible For

The boundary that keeps this domain honest: the browser-executed application and the interaction a person feels — and where everything else properly lives.

Q · Which of these problems is mine, which belongs to a neighbour, and which is shared?

HTML & Semantics

6 lessons

Structured content with behaviour attached. What a `button` gives you that a clickable `div` silently takes away — keyboard, focus, defaults, assistive technology, tooling.

Semantics Are Behaviour
▶ lab

Choosing an element selects a role, a place in the tab order, a set of keyboard defaults, an activation behaviour and an entry in the accessibility tree. `div` selects none of them.

Q · What does the browser actually do differently when I write `button` instead of `div`?
Document Structure and Reading Order
▶ lab

Landmarks, headings and source order are the navigation system most of your users never see — and the one CSS can silently disagree with.

Q · How does someone who cannot see the layout find their way around this page?
What Native Elements Already Do
▶ lab

Activation behaviour, form participation, implicit submission, the top layer and constraint validation — the platform features most component libraries reimplement, more slowly and less completely.

Q · Before I build this component, what does the browser already implement, and what exactly breaks when I take it over?
The Head: Metadata That Changes Rendering
▶ lab

Charset, viewport, lang, title and the link relations decide how the rest of the document is decoded, sized, named, shared and blocked — before a single pixel of body content exists.

Q · Which parts of `<head>` actually change what the browser does, and which are only for other people's crawlers?
Images, Video and the Elements That Own Their Layout
▶ lab

Replaced elements bring their own dimensions, their own bytes and their own decode memory — and nearly every problem they cause is fixed with an attribute rather than with code.

Q · What do the media elements actually do, and which attributes change the browser's work rather than the appearance?
Div Soup: How It Happens and What It Costs
▶ lab

Nobody sets out to write forty nested divs. They arrive one justified wrapper at a time, and the bill is paid in accessibility, style recalculation and JavaScript you had to write yourself.

Q · Why does markup drift towards meaningless nesting, and what does each extra wrapper actually cost?

HTML Parsing & Script Loading

6 lessons

Bytes to tokens to a tree, streaming as it arrives — and what `script`, `defer`, `async` and `type=module` actually do to that stream.

The HTML Tokenizer
▶ lab

Bytes become characters become tokens, through a specified state machine that has no fatal errors and that the tree builder can reach in and reconfigure.

Q · How does a stream of bytes become the start tags, attributes and text the browser works with — and why does malformed HTML never throw?
Tree Construction
▶ lab

Tokens become a DOM through insertion modes and a stack of open elements — which is why the tree the browser built is frequently not the markup you wrote.

Q · Why is the DOM in the Elements panel different from the HTML I sent, and what rules produced the difference?
Streaming HTML
▶ lab

The parser starts on the first chunk and never waits for the last one — which makes time to first byte, flush behaviour and document order performance decisions rather than server details.

Q · If the browser parses HTML as it arrives, what does that change about how I should generate and send it?
Why a Script Tag Stops the Parser
▶ lab

A classic `<script>` suspends tree construction because the script may write into the document at that exact point — and it also waits for pending stylesheets it may never touch.

Q · What exactly happens when the parser reaches a `<script>` tag, and why does the page go quiet?
`defer`, `async` and `type="module"`
▶ lab

Three genuinely different orderings: `defer` keeps document order and runs before DOMContentLoaded, `async` runs whenever it arrives with no order guarantee, and modules are deferred by default.

Q · Which script-loading attribute should this tag have, and what ordering guarantee am I actually getting?
The Preload Scanner
▶ lab

A second, lightweight reader runs ahead of the real parser looking for URLs to fetch — and almost every modern loading pattern accidentally hides resources from it.

Q · If a script stops the parser, how does the browser keep discovering images and stylesheets further down the document — and why does that stop working in my app?

The DOM

6 lessons

The browser's live object model of the document: nodes, attributes, listeners, computed style, layout boxes and the accessibility semantics derived from all of it.

The DOM Is Not Your HTML
▶ lab

A tree of live objects the parser built from your markup and script has since diverged from — each node carrying attributes, properties, listeners, computed style, a layout box and an accessibility role.

Q · What is the browser actually holding for each element, and why does it stop matching the HTML I wrote?
What a Mutation Costs

Which changes invalidate style, which force layout, which repaint and which the compositor can absorb — and why the honest answer to most of them is "it depends what else is on the page".

Q · I changed one property on one element. How much work did I just ask the browser to do?
Queries, Live Collections and Stale References

Some queries return a snapshot, some return a view that keeps changing under you, and some are not questions about the tree at all — they force layout to answer.

Q · When I ask the DOM for a set of elements, what exactly did I get — and will it still be true in a moment?
Node Identity Across Updates

Focus, selection, caret position, scroll, animation progress and uncontrolled input values live on the node object — so whether an update reuses a node or replaces it is a visible product decision.

Q · When the data behind a list changes, how does the browser know that this row is still the same row?
Shadow DOM and the Composed Tree

A second tree attached to a host element: styles do not cross, queries do not cross, events retarget — and id-based accessibility relationships break in ways nothing warns you about.

Q · What does a shadow root actually isolate, and what still crosses the boundary?
Detached Nodes and What Keeps Them Alive

Removing a node from the document frees one reference, not the node — and because nodes point at their parents, siblings and children, one surviving reference retains an entire subtree.

Q · The nodes are gone from the page, so why does memory keep growing?

CSS & CSSOM

6 lessons

Cascade, specificity, inheritance and computed style as a resolution algorithm you can reason about, rather than a fight you win with `!important`.

The CSSOM

Stylesheet bytes become an indexed object model before they become style: how rules are stored for fast lookup, why CSS blocks rendering, and what each runtime way of changing style actually costs.

Q · What does the browser build out of my stylesheet, and why does that structure decide when the page can paint?
The Cascade
▶ lab

Origin and importance, then context, then element-attached styles, then layers, then specificity, then order — a six-step sort that decides every property on every element, in that order.

Q · When two declarations both apply to an element, which one wins, and at which step of the sort did the other one lose?
Specificity
▶ lab

A three-part tuple compared left to right, not a score. What counts, what deliberately counts as zero, and how `:where()` and `:is()` turn specificity into something you choose.

Q · How exactly does the browser compare two selectors, and how do I stop that comparison from being an argument?
Inheritance and Computed Style

From declared value to cascaded, specified, computed, used and actual value — which properties inherit, what `inherit`, `initial`, `unset` and `revert` each mean, and why reading style back can force layout.

Q · After the cascade picks a winner, what does the browser actually store on the element — and why is that not the number I see on screen?
Custom Properties

Inherited properties holding a token stream, substituted at computed-value time — which makes them dynamic, scopeable per element, and capable of invalidating a very large subtree at once.

Q · What is a CSS custom property actually — a variable, a property, or something the cascade participates in — and what does changing one cost?
Selector Matching Cost

How matching actually works, why selector performance is almost never the bottleneck in a modern engine, and what the real cost is: how many elements a change forces the browser to restyle.

Q · Do my selectors make style calculation slow — and if not, what does?

The Rendering Pipeline

6 lessons

DOM plus CSSOM to style to layout to paint to composite — and the invalidation rules that decide which of those stages a given change actually costs you.

The Rendering Pipeline
▶ lab

DOM plus CSSOM become computed styles, then geometry, then paint commands, then a composited frame — and most updates re-run only part of that.

Q · What does the browser actually do between a change to the page and a new frame on the screen?
Style Calculation

Selector matching, cascade resolution and inheritance turn every rule you shipped into exactly one computed value per property, per element.

Q · What is the browser computing during the style stage, and what actually makes that computation expensive?
Style Invalidation

A change does not recalculate the document — it dirties a set of elements. The size of that set is the cost, and your selectors are what decide it.

Q · When something changes, how does the browser decide which elements need their style recomputed?
The Cost of a Change
▶ lab

The table you should be able to reconstruct from first principles: which stages each common change invalidates, and why the honest answer is so often "it depends".

Q · For this specific change, which stages of the rendering pipeline does the browser actually have to re-run?
CSS Containment

`contain` is a promise you make to the engine — nothing inside this box affects anything outside it — and in exchange, invalidation stops at the boundary.

Q · How do I tell the browser that a subtree cannot affect the rest of the page, and what am I giving up by saying so?
content-visibility

Ask the engine to skip rendering work for content nobody is looking at yet — and take on responsibility for its size, its scrollbar and whether anyone can find it.

Q · Can the browser simply not render the parts of the page nobody can see, and what does that cost me?

Layout

7 lessons

Geometry: the box model, normal flow, flexbox, grid, positioning, intrinsic sizing, overflow — and the read-write-read pattern that forces the browser to compute it all again.

The Box Model

Every element is four nested edges — content, padding, border, margin — plus a sizing mode that decides which of them `width` is actually describing.

Q · When I set `width: 300px`, what exactly is 300 pixels wide, and why does the element occupy more space than that?
Normal Flow, Overflow and Margin Collapsing

What the browser already does before you choose a layout mode: block and inline formatting, margins that merge, and the moment a box becomes a scroll container.

Q · Before I reach for flexbox, what is the browser doing by default — and where does the content go when it does not fit?
Flexbox: One Axis at a Time
▶ lab

A distribution algorithm, not a property list: base sizes, free space, grow and shrink along the main axis, alignment along the cross axis.

Q · What is flexbox actually computing when I write `flex: 1`, and why does one long item push everything else out of the way?
Grid: Two Dimensions at Once
▶ lab

The container declares tracks and lines; items are placed into the cells between them. Rows can finally align to columns, because the layout — not the content — owns the sizes.

Q · When is a two-dimensional layout the right model, and what is `1fr` actually a fraction of?
Positioning and Stacking Contexts

Taking a box out of flow: which ancestor it is positioned against, and why `z-index: 9999` still loses to a header with `z-index: 1`.

Q · Which box am I positioned relative to, and why is my dropdown still behind the header?
Intrinsic Sizing and the Automatic Minimum

What a box wants to be when nobody tells it: min-content, max-content, fit-content — and the `min-width: auto` rule that makes flex and grid items overflow.

Q · What size does a box choose on its own, and why does a flex item refuse to shrink below its longest word?
Layout Thrashing
▶ lab

Read a layout property, write a style, read again: each read forces the browser to recompute the geometry you just invalidated, synchronously, inside your loop.

Q · Why does a loop that only reads two properties per element cost more than the render it triggers?

Paint & Compositing

6 lessons

Paint commands, layers, the compositor thread and the frame budget. Why `transform` and `opacity` are often cheaper to animate, stated as a mechanism rather than a slogan.

Paint Commands

Painting does not produce pixels directly: it records an ordered list of drawing commands per layer, which a rasteriser later turns into bitmaps.

Q · When the browser "paints", what is it actually producing, and why does filling the same rectangle sometimes cost ten times more than filling it a different way?
Compositing Layers

A layer is a separately rasterised surface the compositor can transform and blend on its own thread — powerful, conditional, and paid for in memory.

Q · What is a compositing layer, what causes one to exist, and what does the compositor get to do with it that the main thread would otherwise have to?
Cheap and Expensive Animation

Why `transform` and `opacity` can be driven by the compositor without the main thread — stated as a mechanism, with the conditions under which it is simply not true.

Q · What actually makes an animated property cheap, and when does the advice to animate `transform` and `opacity` stop being correct?
The Frame Budget
▶ lab

A display refreshing 60 times a second gives roughly 16.7ms per frame — a useful baseline that shrinks on faster displays and is shared with the browser's own work.

Q · How much time does a frame actually give me, and how much of it is genuinely mine?
Scroll and Input Latency

Scrolling is handled by the compositor when it can be, and by the main thread when your code forces it — which is why one listener can make a whole page feel broken.

Q · Why does scrolling stay smooth on a busy page sometimes and stutter badly other times, and what decides which?
Layer Explosion

Promoting everything with `will-change` trades main-thread paint for GPU memory and per-frame compositing — and past a small number of layers that trade inverts.

Q · If layers make animation cheap, why does adding `will-change` to more elements make the page slower?

The Browser Event Loop

7 lessons

Call stack, task, microtask checkpoint, rendering opportunity. The scheduling model that explains why a synchronous loop freezes the page and a promise chain does not yield a frame.

The Event Loop, Precisely
▶ lab

One call stack, task queues, a microtask checkpoint that drains to empty, and a rendering opportunity between tasks — the model that predicts any ordering puzzle.

Q · Why does this code print A, D, C, B — and what makes that ordering a guarantee rather than an accident of implementation?
Tasks: The Unit That Cannot Be Interrupted
▶ lab

Where tasks come from, why each one runs to completion, and why `setTimeout(fn, 0)` is neither zero nor a promise about when.

Q · What exactly is a task, which browser activities produce one, and what does "runs to completion" cost me?
The Microtask Checkpoint
▶ lab

Drained to empty after every callback, including microtasks queued during the drain — which is exactly why an unbounded promise chain freezes a page with no long task to blame.

Q · When does a promise callback actually run, and how can a page hang without a single long task in the profile?
The Rendering Opportunity
▶ lab

A frame can only be produced between tasks, after the microtask checkpoint — which is the mechanical reason a promise chain never lets the browser paint.

Q · When exactly can the browser produce a frame, and why does my loading state never appear before the work that was supposed to follow it?
Long Tasks
▶ lab

One task that runs long blocks input, rendering and accessibility-tree updates at the same time — which is why "the page froze" is one symptom with one cause.

Q · What is actually happening to the user while one of my tasks is running, and how do I find the task responsible?
What the Main Thread Owns
▶ lab

Script, DOM, style, layout, event dispatch and the accessibility tree share one thread — and knowing what is not on it is what makes moving work possible.

Q · Which work must happen on the thread that owns the DOM, and which work is already somewhere else?
Yielding and Scheduling
▶ lab

Breaking work into pieces the loop can get between — with honest limits: zero is not zero, idle callbacks are not everywhere, and the newer scheduling APIs are not yet universal.

Q · How do I break long work into pieces the browser can interleave with input and rendering, and which primitive should I actually use?

Workers & Off-Main-Thread Work

5 lessons

Moving CPU work off the thread that owns the DOM: message passing, structured clone, transferables, and the isolation requirements the sharper primitives carry.

Browser Events

6 lessons

Dispatch, capture, target, bubble. Delegation, default actions, pointer and keyboard input, and why cancelling the wrong thing breaks scrolling or accessibility.

How an Event Is Dispatched
▶ lab

Hit-test to a target, build the propagation path, then walk it: capture down, at target, bubble up — with the path frozen before any listener runs.

Q · When a user clicks, how does the browser decide which code runs, and in what order?
Event Delegation

One listener on a container instead of one per row: fewer registrations, no rebinding after a re-render, and a matching step you now own.

Q · When a list has a thousand rows and each needs a click handler, where should the listener actually go?
preventDefault vs stopPropagation

Two operations that share nothing: one cancels what the browser was about to do, the other stops the event travelling. Reaching for the wrong one breaks somebody else's feature, silently.

Q · The browser did something I did not want, or my handler ran twice — which of these two calls is the fix, and what does the other one break?
Pointer Events

One event model for mouse, touch and pen — plus pointer capture, gesture cancellation, and the unrelated CSS property that shares the name.

Q · How do I write one interaction that works with a mouse, a finger and a stylus without three code paths?
Keyboard Events

Why Enter and Space activate a native button on different events, why a clickable div gets neither, and why `key` and `code` answer different questions.

Q · What does the browser do for keyboard users on a `<button>` that it does not do for my `<div onclick>`?
Passive Listeners

A `touchstart` or `wheel` listener can hold a scroll hostage until it has run. `{ passive: true }` is a promise not to cancel — and browsers now assume it in places, which changes what your code does.

Q · Why does adding an empty scroll-related listener make scrolling stutter, and what does `{ passive: true }` actually promise?

Forms

6 lessons

The platform's oldest interactive component: input types, native validation, submission, focus order, labels — and what you inherit for free before any framework state exists.

Native Forms First

A `<form>` ships with submit-on-Enter, validation, autofill, password-manager integration and a label/control relationship. Most custom forms are a worse reimplementation of it.

Q · What does a real `<form>` element already do, and how much of it am I about to rewrite by accident?
Input Types, Inputmode and Autocomplete

The right `type`, `inputmode` and `autocomplete` change the on-screen keyboard, the autofill offer and the validation the browser runs — a large UX win for one attribute.

Q · Which attribute actually changes what a user sees when they tap a field, and what does each of them control?
Native Validation and Its Limits

The Constraint Validation API gives you checks, states and messages for free — then runs out at styling, wording and timing. Replacing it means re-implementing what it did well.

Q · What does the browser check for me, where does that stop being enough, and what am I taking on when I switch it off?
Controlled vs Uncontrolled Inputs

Either your framework owns every keystroke or the DOM does and you read at submit. A real trade-off between per-keystroke render cost and reactive capability — not a rule.

Q · Should the current value of this field live in framework state, or in the DOM until I need it?
Submission: Method, Encoding and Doing It Once

GET versus POST is a semantic choice with cache and history consequences; `FormData` and `enctype` decide what goes on the wire; and preventing the second submit is your job.

Q · What actually happens when this form is submitted, and how do I make sure it happens exactly once?
Errors People Can Actually Perceive

An error must be programmatically tied to its field, announced when it appears, reachable by focus and expressed in more than colour. Red text is not an error state.

Q · When a field is wrong, how does every user — including one who cannot see the screen — find out what is wrong and where?

Accessibility

8 lessons

DOM plus semantics plus ARIA becomes an accessibility tree that assistive technology reads. Keyboard operation, focus management and announcement are engineering requirements, not a later pass.

The Accessibility Tree
▶ lab

The browser derives a second tree from the DOM — role, name, state and relationships — and hands it to the platform. That tree, not your markup and not your pixels, is what assistive technology reads.

Q · What does assistive technology actually read, and where does it come from?
Semantics Before ARIA

The first rule of ARIA is not to use ARIA. A native element brings role, focusability, keyboard behaviour and default actions; ARIA brings a label in a tree and nothing else.

Q · Why is a native element better than a `div` plus ARIA, when the accessibility tree ends up looking the same?
Keyboard Operability

Every interaction must be reachable, understandable and completable with a keyboard alone — because the keyboard is also the switch device, the voice command, the braille display and the screen reader.

Q · Can a person reach, understand and complete every flow in this interface without a pointer?
Focus Management

Focus is a single pointer into the document that the browser maintains for you — until your application replaces the DOM underneath it. Then it becomes yours to move, contain and restore.

Q · Where is focus right now, where should it go next, and who is responsible for putting it there?
The Rules of ARIA

ARIA has a small set of rules that exist because each one describes a real way people break pages. The underlying one: a wrong ARIA attribute is worse than no ARIA at all, because the browser will faithfully repeat your mistake.

Q · What are the actual rules for using ARIA, and why is wrong ARIA worse than none?
Live Regions and Announcement

Nothing announces itself. A DOM change away from the user's focus is silent unless it happens inside a region the assistive technology was already watching — and announcing everything is its own failure.

Q · Something changed on the page and the user was not looking at it. How do they find out — and how do I avoid telling them about everything?
Contrast, Colour and Motion

Perceivability is measurable and it is a user preference. Contrast has a computed value, colour must never be the only carrier of meaning, and motion, contrast and target size are all things the operating system already knows about the person using your page.

Q · Can this interface be perceived by someone with low vision, colour vision deficiency, a vestibular disorder or an imprecise pointer?
Accessible Component Patterns
▶ lab

The lab: modal, menu, tabs, accordion and form, each written as a contract — semantics, keys, focus and announcement — because a component that does not state these has not specified its behaviour at all.

Q · What exactly does each of the standard interactive components owe a keyboard and a screen reader?

Responsive Design

6 lessons

Adapting to available space and user conditions: fluid layout, media and container queries, responsive images, CSS pixels versus device pixels, and typography that survives translation.

Fluid Layout First

Percentages, `min()`, `max()`, `clamp()` and the intrinsic behaviour of flex and grid express continuous adaptation; a breakpoint is what you reach for when the change genuinely cannot be continuous.

Q · How do I build a layout that fits every width, rather than the five widths I happened to test?
Media Queries Beyond Width

Width is one axis. Colour scheme, reduced motion, contrast, pointer precision, hover capability and orientation are separate questions — and the preference ones are accessibility features, not theming.

Q · What can I actually ask the browser about the user's conditions, and which of those answers am I obliged to respect?
Container Queries

A component should respond to the space it was given, not to the viewport it happens to be inside — which is why `container-type` establishes containment, and why that containment has real layout consequences.

Q · The same card is in a wide main column and a narrow sidebar. How does it know which one it is in?
Responsive Images

`srcset` and `sizes` for resolution switching, `<picture>` for art direction and format, `loading` and `decoding` for scheduling — and `width`/`height` or `aspect-ratio` always, so the browser can reserve the space.

Q · How do I send each user an image that is the right number of pixels, in a format their browser can decode, without the page jumping when it arrives?
The Viewport and Device Pixels

CSS pixels, device pixels and the ratio between them; the layout viewport versus the visual viewport; the one viewport meta tag worth writing — and why suppressing zoom is an accessibility failure, not a layout fix.

Q · When I write `16px`, what does that mean on a phone with a 3x screen, on a laptop at 150% OS scaling, and on a page a user has zoomed into?
Responsive Typography

Fluid type with `clamp()` that still honours the user's font size, a measure defined in characters rather than pixels, and layouts that survive a translation two-thirds longer than the English it was designed around.

Q · How do I make text scale with the space available without breaking zoom, readability, or the German build?

State

7 lessons

Local, form, URL, server, auth, cached and persistent state are different things with different owners. Most frontend bugs are a state-ownership answer nobody wrote down.

The Seven Kinds of State

Local UI, form, URL, server, authentication, cached and persistent state have different owners, lifetimes and truths. Calling them all "state" is the first bug.

Q · What kind of state is this, and who should own it?
Who Owns This State?
▶ lab

A five-criterion decision — shareable, local-only, server-authoritative, distant, or must-survive-reload — that resolves most state placement questions before a library is chosen.

Q · Where should this particular value live, and what decides that?
The URL Is Application State

Filters, tabs, pagination and the selected item belong in the address bar far more often than teams assume — because that is the only state store the browser itself restores.

Q · Which parts of what the user is looking at should be encoded in the URL?
Derived State

If a value can be computed reliably from state you already hold, storing it separately creates a second owner — and duplicated state is state that can disagree with itself.

Q · Should I store this value, or compute it from what I already have?
State Synchronization

The server, the client cache, component state and the URL can all hold a version of the same fact. When they disagree, the only question that matters is which one is authoritative.

Q · Four places hold a version of this value and they disagree — which one is right, and how did they diverge?
Form State Is a Draft

A form is a staging area for a mutation that has not happened yet: the user is authoritative until submit, dirtiness is the tracked fact, and the record is only replaced when the server agrees.

Q · While someone is filling in a form, who owns those values — and what happens to them if they leave?
Persistent Client State

What survives a reload, a tab discard, a browser restart and a new device are four different questions — and anything you persist is a schema you now have to migrate.

Q · What should still be here after a reload, a crash, a week away, or a switch to another device?

Component Architecture

6 lessons

Boundaries drawn by responsibility, state ownership and reuse — plus the contract a component owes: inputs, events, slots, behaviour and accessibility.

Drawing Component Boundaries

Six forces decide where a component ends — responsibility, state ownership, composition, reuse, render cost and accessibility — and "this file is getting long" is not one of them.

Q · Where should one component end and the next begin, and which force is actually making that decision?
What a Component Owes Its Caller

Inputs, outputs, slots, behaviour and accessibility are all part of the API. The a11y half is the half that gets left implicit, and that is where components break.

Q · What exactly does a component promise, and which of those promises are written down in its type?
Composition and Slots

Children are the mechanism that stops a component growing a prop for every possible variation. Compound components and scoped slots are what you reach for when the frame needs to talk to the filling.

Q · When a component needs to vary, should the caller pass another prop or pass content?
Prop Drilling, Context and Global State

Three ways to get a value from where it lives to where it is needed. Each buys something and each charges for it, and none of them is the default answer.

Q · This value lives four levels up from where I need it. What is the honest cost of each way of getting it there?
Over-Componentization

Indirection with no behaviour: a component per div, props that only pass through, and a stack ten frames deep to render one button.

Q · When has splitting things up stopped helping, and what does the excess actually cost?
What a Component Costs to Render

Framework work and browser work are two different bills. Re-running a component is cheap; mutating the DOM, invalidating style and forcing layout are not — and most components are not your bottleneck.

Q · When a component re-renders, what does the framework do, what does the browser do, and which of the two is actually costing me?

Frameworks & Reactivity

8 lessons

React, Vue, Svelte, Solid and Angular as different answers to the same questions: how change is detected, how much work is compile-time, and what reaches the DOM.

Reactivity Models
▶ lab

Re-run and diff, tracked proxies, compile-time analysis, fine-grained signals, zone-based change detection: five ways of finding out that something changed.

Q · How does a framework find out that something changed, and what does each answer cost?
The React Mental Model

State and props go in, the component function runs and returns a description of the UI, a reconciler compares descriptions, and the difference becomes DOM calls.

Q · What actually happens between calling a state setter and a pixel changing in React?
The Vue Mental Model

Reactive state records who read it. A component re-renders when a reactive value it actually read during its last render has changed — not because its parent did.

Q · How does Vue know which components to re-render, without being told?
The Svelte Mental Model

A compiler reads your component, works out which parts of the markup depend on which values, and emits code that updates exactly those parts.

Q · What can a build step know about my UI that a runtime cannot, and what does it do with that knowledge?
The Solid Mental Model

The component function runs once. Signals hold values with subscriber lists, and setting one re-runs only the small computations that read it — each writing to the node it owns.

Q · What changes when the component function never runs a second time?
The Angular Mental Model

An integrated framework rather than a view library: components and templates, dependency injection, routing, forms and a build system, shipped and versioned together.

Q · What does it mean for the framework to supply the whole application structure, not just the rendering?
Reconciliation and Keys

Deciding what changed between one UI state and the next comes down to identity: which node in the new list is the same thing as which node in the old one.

Q · How does a framework decide whether to update a node or replace it, and what does it use to tell items apart?
Choosing a Framework

There is no winner. There are constraints — team, existing code, hiring, rendering strategy, bundle budget, support horizon — and the framework that fits the most of yours.

Q · Given what my team, my product and my users actually need, how do I choose, and what am I signing up for?

Client-Side Routing

6 lessons

The URL is application state — shareable, bookmarkable and restorable. Route matching, nesting, history, scroll restoration and the loading boundaries in between.

Client-Side Routing

Intercept the link, match the URL, swap the view — and inherit every job the browser was quietly doing during a real navigation.

Q · What does a client router actually replace, and what does the browser stop doing for me the moment I intercept a link?
Route Matching

How a path becomes a route: segmentation, patterns, specificity, ranking versus ordering, and the nested match chain that renders a page.

Q · Given a URL, how does a router decide which route owns it — and why do two routes ever both look right?
URL Parameters

Path params identify, query params refine — and both are untrusted strings that have to be parsed, validated and canonicalised before anything renders.

Q · What belongs in the path, what belongs in the query string, and who is responsible for the fact that all of it is a string typed by a stranger?
History and Navigation

The session history stack, `pushState` versus `replaceState`, `popstate`, and why intercepting navigation without handling back is the most common router bug there is.

Q · What does the history stack actually hold, and why is the back button the hardest part of a client router to get right?
Scroll Restoration

The browser does this well and single-page applications break it: `history.scrollRestoration`, restoring on back but not on a forward navigation, and the async data problem that puts you in the wrong place.

Q · Why does back land in the wrong place in my single-page application when the same site got it right as a set of ordinary documents?
Route Loading Boundaries

Where the spinner belongs: the subtree a fallback is allowed to replace, why nesting them matters, and why one boundary at the top blanks the whole page on every navigation.

Q · Where should the loading state live, and why does my entire page go blank every time someone clicks a link?

Data Fetching & Server State

7 lessons

Request, loading, success or error, render — and the parts that only show up in production: cancellation, deduplication, retries, pagination and background refresh.

The Life of a Fetch
▶ lab

Request, loading, success or error, render — and the fact that `fetch` resolves happily for a 500, has no deadline, and hands you a body you still have to parse.

Q · What actually happens between calling `fetch` and rendering data, and which of those steps can fail without ever throwing?
Loading, Error, Empty — The States You Did Not Render
▶ lab

An interaction has at least four states and usually five. The missing failure branch is the most common defect in frontend code, and empty is not loading.

Q · How many states does a piece of remote data actually have, and which of them is my interface silently missing?
Cancelling a Request Nobody Is Waiting For
▶ lab

`AbortController`, unmount, and the `AbortError` that must never be shown to a user — because abandonment is not failure.

Q · How do I stop a request whose answer nobody wants any more, and why must the error it produces never reach the user?
Five Components, One Request
▶ lab

In-flight coalescing and caching are two different mechanisms with two different windows. Confusing them is why "we have a cache" does not stop the thundering herd on mount.

Q · Five components mount and each asks for the same user — how many requests should leave the browser, and which mechanism prevents the other four?
Retries, and the Duplicate Order
▶ lab

Retrying a non-idempotent mutation is a correctness bug wearing resilience as a costume. Retry only what is safe, with backoff, jitter and a cap.

Q · Which failed requests may I retry automatically, and what turns a retry from resilience into a second charge on someone's card?
Pagination From the Interface Backwards
▶ lab

Offset gives you jump-to-page and gives you duplicates under insertion. Cursor gives you stability and takes away page numbers. Pick from the UI you owe, not from the API you were given.

Q · Offset or cursor — which one does the interface I am building actually require, and what does the other one make impossible?
Server State Is Not Your State
▶ lab

It has freshness, a cache, invalidation, refetching, synchronisation and an authority that lives somewhere else. Copy it into component state and it starts diverging immediately.

Q · Which of the values in my components are actually owned by a server, and what changes the moment I admit that?

Client Cache & Optimistic UI

6 lessons

Query keys, freshness, staleness and revalidation; updating the interface before the server has agreed, and reconciling honestly when it does not.

The Client Cache Model
▶ lab

A key, an entry, a freshness state and a revalidation rule — the cache your application owns, which is not the browser's HTTP cache and does not obey its headers.

Q · When my application already has this data, what decides whether it asks the server for it again?
Query Keys and Invalidation
▶ lab

The key is the identity of the data. Deduplication, hits, cross-contamination and the blast radius of every invalidation are all decided by what you put in it.

Q · What exactly identifies this piece of server data, and what should happen to it when something changes?
Stale-While-Revalidate
▶ lab

Render what you have, fetch what is current, write it in — and take responsibility for the fact that the page changed under the person reading it.

Q · Should I show the user data I already have while I check whether it is still true?
Optimistic UI
▶ lab

Updating the interface before the server has agreed: a claim the client makes on the authority's behalf, acceptable exactly when the rollback is honest.

Q · When is it right to show the user that something happened before the server has confirmed that it did?
Rollback and Reconciliation
▶ lab

The server rarely just says yes or no. It says something slightly different — and reverting your prediction is usually the wrong answer to that.

Q · The server accepted my mutation and returned something other than what I predicted. Now what?
Out-of-Order Responses
▶ lab

"cat" then "car": A leaves first, B returns first, A returns last and overwrites the newer result with the older one. The fix is a rule about which response is allowed to win.

Q · Two requests are in flight for the same piece of the interface. Which response is allowed to write to the cache?

Real-Time UI

6 lessons

Polling, long polling, SSE and WebSocket compared by what they cost — plus reconnect, ordering, duplicate delivery and the resynchronisation nobody prototypes.

Choosing a Real-Time Transport

Polling, long polling, SSE and WebSocket compared by direction, connection cost, infrastructure friction, reconnection, framing and what the browser already does for you.

Q · Which transport does this feature actually need, and what does each one cost me after the prototype works?
Server-Sent Events

One-way, text, and reconnecting by default: what `EventSource` does for you, how `Last-Event-ID` closes a gap, and the per-origin connection limit that only bites in the fifth tab.

Q · When is a one-way text stream with reconnection already built in the right answer, and what is the trap that only appears in production?
WebSockets in the UI

Bidirectional, framed, and no longer HTTP — which means heartbeats, reconnection, backoff, auth on connect, message schema and versioning are now yours.

Q · What exactly did I take on when I replaced request/response with an open connection?
Reconnect and Backoff

Exponential backoff with jitter, why a server restart without jitter produces a synchronised stampede, and how to say "reconnecting" to a user without saying it a hundred times.

Q · The connection dropped — how soon should I try again, and what happens when every client asks that question at the same instant?
Ordering and Duplicate Delivery

At-least-once is the normal case: events arrive twice, arrive late, and arrive in an order nobody promised. The UI's job is to be idempotent per event.

Q · If the same event can arrive twice and two events can arrive backwards, what does my reducer have to look like?
Resynchronisation After a Gap

The disconnect left a hole. Replay from a cursor or refetch a snapshot — but never resume as if nothing was missed, which is what everybody ships first.

Q · The connection is back. What happened while it was gone, and how do I get this client to the truth?

Frontend Authentication

6 lessons

Representing identity, sending credentials safely, surviving session expiry and rendering authorization-aware UI — while the backend stays the only authority.

What the Frontend Is Responsible For in Auth

Four jobs — represent identity, send credentials safely, survive expiry, render authorization-aware UI — and one job that is never yours: enforcement.

Q · If the server is the only thing that can enforce anything, what is the frontend actually responsible for in authentication?
Cookies vs Script-Readable Tokens

A genuine trade-off with no universal winner: unreadable-but-automatic against readable-but-explicit, and the attributes that decide what each one actually costs you.

Q · Where should a credential live in the browser, and what does each choice give an attacker who gets a foothold?
Session Expiry and the Refresh Race

What the interface does when the credential dies mid-session: silent refresh, five simultaneous 401s that must produce one refresh, and the difference between expired and revoked.

Q · The credential stops working while the user is halfway through something — what should the interface do, and what must it not do five times at once?
Authorization-Aware UI

Render what the user can actually do, so the interface is honest — then let the server refuse the request anyway, and stop leaking the existence of what they cannot see.

Q · How do I show each user an interface that matches their permissions, without ever mistaking that for permission?
Auth Across Tabs

One session, several documents, no shared memory: logging out in one tab has to reach the others, and the tab that missed the message is still rendering a logged-in UI.

Q · The user has five tabs open and logs out in one of them — what happens in the other four, and what should?
Login Redirects and the Open-Redirect Trap

Send the user back to what they were trying to reach — and never redirect to a URL somebody handed you in a query parameter.

Q · How do I return a user to where they were going after logging in, without turning my login page into a redirector for anywhere on the internet?

Frontend Security

9 lessons

XSS, CSRF, the same-origin policy, CORS, CSP, clickjacking, third-party scripts and supply chain — the browser-side half of a problem the server cannot solve alone.

The Browser Security Model

The origin as the unit of trust, the renderer as a sandbox, and four separate mechanisms answering four separate questions — mixing them up is why security fixes so often do nothing.

Q · What does the browser actually enforce on my behalf, and which mechanism answers which question?
The Same-Origin Policy

Embedding is allowed, reading is not — and the gap between "the request was sent" and "your code may see the answer" is where most browser security confusion lives.

Q · What exactly is my page prevented from doing to another origin, and what is it still perfectly free to do?
Cross-Site Scripting

Untrusted content becomes executable content. Your framework already escapes text interpolation — so every XSS in a modern application is at the exact place someone opted out.

Q · Which places in my UI turn data into code, and what is my framework already doing about it?
Sanitization and Trusted HTML

Escaping and sanitization are different operations solving different problems — and when you genuinely must render HTML, allowlist it, at render time, with something you did not write.

Q · I actually need to render HTML from an untrusted source. What is the correct way to do that?
Cross-Site Request Forgery

The browser attaches credentials to requests automatically, including ones another site caused. That helpfulness is the vulnerability, and it is why the defence has to be explicit.

Q · Why can another site make my API call succeed, and which defence matches my architecture?
CORS

A browser policy about whether script may read a cross-origin response. Not authentication, not a firewall, and not relevant to anything that is not a browser — plus the error message that lies to you.

Q · What is CORS actually deciding, and why does my console blame it for a server error?
Content Security Policy

A browser-enforced allowlist for what your page may execute and load. It caps the damage of an injection you missed — and `unsafe-inline` in the script directive turns the whole thing off.

Q · What can a Content Security Policy actually stop, and how do I ship one without breaking the application?
Clickjacking and Framing

Your interface, rendered inside someone else's page, with their content on top. The defence is one response header — and the wrong version of it locks out keyboard users instead.

Q · Who is allowed to put my page in a frame, and what can they do to a user who clicks in it?
Third-Party Scripts and the Supply Chain

A script tag grants full authority over your page. There is no partial trust, and the dependency you never chose is running in the same context as your login form.

Q · What am I actually granting when I add someone else's code to my page?

Browser Storage

6 lessons

Cookies, localStorage, sessionStorage, IndexedDB and Cache Storage: lifetime, synchronicity, capacity and exposure. Four different answers to "where does this live".

Choosing Browser Storage
▶ lab

Cookies, localStorage, sessionStorage, IndexedDB and Cache Storage compared on the six axes that actually decide: lifetime, scope, capacity, synchronicity, automatic transmission and exposure.

Q · Where should this piece of data live in the browser, and what am I signing up for when I put it there?
Cookies
▶ lab

The only browser store the network sends for you. That single property explains the convenience, the size limits, the scoping attributes and the class of attack built on top of it.

Q · What makes a cookie different from every other place I could put this, and what does it cost on every request?
localStorage and sessionStorage
▶ lab

A synchronous, string-only, origin-scoped map. The convenience is real, and so is the fact that every read and write blocks the thread that owns rendering.

Q · What am I actually doing to the main thread when I call `localStorage.getItem`, and why is `sessionStorage` not shared with the tab next to it?
IndexedDB
▶ lab

Asynchronous, structured, transactional and versioned — a real database in the browser, with a schema you own and a migration path that is where real applications break.

Q · When does client-side data need a transactional, versioned store, and what does owning a schema in the browser actually commit me to?
Cache Storage
▶ lab

A script-controlled store of Request/Response pairs. A different layer from the browser's HTTP cache, with different rules, and the reason a service worker can answer a request with no network at all.

Q · How is Cache Storage different from the HTTP cache the browser already has, and what do I gain by taking that decision away from the browser?
Storage Security and Durability
▶ lab

Two properties decide everything here: anything script can read, every script on the origin can read — and nothing in the browser is durable storage.

Q · Who can read what I put in browser storage, and what happens when the browser decides it needs the space back?

Service Workers & Offline

6 lessons

A programmable proxy between the page and the network: install, activate, fetch, update — plus offline mutation queues and the conflict resolution they imply.

The Service Worker Lifecycle
▶ lab

Install, activate, fetch, update — and the waiting worker that quietly leaves users running last week's code for days.

Q · I deployed a fix an hour ago and users are still hitting the old bug — what version of my site is actually running in their browser?
Intercepting Fetch
▶ lab

The worker sits between the page and the network and can answer from cache, from the network, or with a response it invents — which is exactly why it can brick your site.

Q · Once a service worker controls my page, what actually happens to a request — and what happens if my handler is wrong?
Caching Strategies
▶ lab

Cache-first, network-first, stale-while-revalidate, cache-only, network-only: five answers, each right for something and each with a characteristic way of going wrong.

Q · For this particular request, should the cache or the network answer first — and what does the user get when the answer is wrong?
Offline UX
▶ lab

Honesty is the whole lesson: say what is available, what is stale, what is queued, and what will happen on reconnect — because a UI that pretends to be online is worse than one that admits it is not.

Q · The network is gone or unreliable — what does the interface owe the person using it?
The Offline Mutation Queue
▶ lab

Change offline, persist locally, reconnect, sync, resolve conflicts — and the last step is a product decision, not a technical default.

Q · A user changed something with no network. Where does that change live, in what order does it reach the server, and who decides what happens when the server disagrees?
Manifest and Installability
▶ lab

What the manifest declares, what makes a site installable, and why an installed app with no offline story is just a bookmark with an icon.

Q · What does it take for a site to be installable, and what does installing it actually change for the user?

Performance & Web Vitals

9 lessons

Loading, interaction responsiveness and visual stability measured on real devices, with the main-thread and memory work behind each one. Measure before optimising, always.

Measure Before Optimising
▶ lab

Lab profiles and field data are two instruments answering two different questions. Which browser signal to reach for, and why a local recording is a hypothesis rather than evidence.

Q · Before I change any code, which signal tells me what is actually slow for the people using this?
Loading: Why Content Arrives Late
▶ lab

The main content has to be discovered, requested, delivered and unblocked before it can paint. Late is usually a discovery or a blocking problem, not a byte problem.

Q · The main content of this page appears late — which of the steps between the request and the pixel is holding it up?
Interaction Responsiveness
▶ lab

A slow tap is three separable delays: waiting for the thread, running the handler, and producing the frame that shows the result. Each has a different fix.

Q · When a tap or a keystroke feels slow, which of the three phases between the input and the pixel is actually slow?
Visual Stability
▶ lab

Content moves because something arrived after layout had already been decided. Reserve the space before the content exists, and the shift never happens.

Q · Why does content jump around while the page is loading, and what would have to be true for it not to?
The Real Cost of JavaScript
▶ lab

Bytes are only the download. Parse, compile, execute and retain all cost more, they all scale with the device, and execution competes with rendering for the one thread that can paint.

Q · My bundle is smaller than it was and the app is not faster — what does shipping JavaScript actually cost?
Images and Fonts
▶ lab

The two heaviest things on most pages, and the two most often shipped at the wrong size, in the wrong format, discovered too late, and without any space reserved for them.

Q · How do I get the right pixels and the right glyphs to the user quickly, without moving anything that is already on screen?
Memory Leaks
▶ lab

The app is fine on load and slow an hour later. Something is being retained on every interaction and released on none.

Q · Why does it get slower the longer someone leaves it open?
List Virtualization
▶ lab

A hundred thousand rows of data, about thirty rows of DOM. It is the right answer for large lists and it costs you real things.

Q · The table has 100,000 rows and the page is unusable. What do I actually do?
Memoization

Trading recomputation for memory and an invalidation problem. Sometimes clearly worth it; applied everywhere, a net loss with extra bugs.

Q · Should I memoize this, and how would I know?

Critical Path & Delivery

7 lessons

The waterfall from HTML to first content: blocking resources, resource hints, HTTP caching, CDNs and content-hashed assets — the network half of how fast a page feels.

The Critical Rendering Path

The set of resources that must arrive and be processed before the browser can paint meaningful content — a dependency graph, not a byte count.

Q · Which resources must arrive before the browser can paint anything meaningful, and what put them on that list?
Reading a Network Waterfall

Bars are not the point. The staircase is: a resource that could not start until another finished is a dependency your page structure created, and often one you can delete.

Q · When I open the Network panel, what am I actually looking for?
Render-Blocking Resources

Three different mechanisms produce one symptom. CSS blocks painting, synchronous scripts block parsing, and scripts wait on pending stylesheets — and each has a different fix.

Q · What exactly is the browser refusing to do while it waits for this resource, and why?
Resource Hints

`preconnect`, `dns-prefetch`, `preload`, `modulepreload` and `prefetch` are five different jobs — and a hint that guesses wrong costs more than no hint at all.

Q · How do I tell the browser about a resource before it would have discovered it, and when is doing so a net loss?
Browser HTTP Caching

What the browser does before it makes a request at all: freshness, `no-cache` versus `no-store`, validators, revalidation, and `immutable`.

Q · When does the browser skip the network entirely, when does it ask "has this changed?", and what decides which?
CDN Delivery

Build output to an edge near the user: what the cache key is made of, why invalidation is a worse tool than versioning, and why edge caching is mostly about latency rather than bandwidth.

Q · What actually happens between my build output and a byte arriving at a user's device, and which part of it can I control?
Content-Hashed Assets

`app.a3f19c.js` is a caching strategy, not a naming convention: you never invalidate a URL, you stop referencing it — with consequences for code splitting and for tabs that have been open all week.

Q · How do I cache an asset for a year and still be able to change it tomorrow?

Build Tooling & Bundling

11 lessons

Modules to dependency graph to transforms to chunks. Code splitting, tree shaking, TypeScript, polyfills versus transpilation, source maps, and what your users download.

The Module Graph
▶ lab

Entry points become a dependency graph, the graph is transformed, and the graph is cut into chunks. Every bundler is an implementation of those three ideas.

Q · What does a build tool actually do between my `import` statements and the files a browser downloads?
Bundlers Compared
▶ lab

Vite, Webpack, Rollup, esbuild and SWC as implementations of the same graph-and-chunks model, separated by dev-server strategy, build speed, plugin surface and output control.

Q · These tools all produce JavaScript files — what actually differs between them, and which difference should decide anything?
Code Splitting
▶ lab

Cutting one graph into an initial chunk plus route and feature chunks — and the two failures on either side of it: shared code duplicated, and a waterfall of tiny chunks.

Q · My application ships as one large file that every user downloads in full. How do I cut it up without making things worse?
Lazy Loading
▶ lab

Deferring routes, components, images and expensive modules until they are needed — and the loading state, the flash and the error path that every deferral creates.

Q · Which parts of this page can I load later, and what do I owe the user in the gap I just created?
Tree Shaking
▶ lab

Static module analysis can allow unused exports to be dropped — and five specific things routinely stop it: side effects, a wrong `sideEffects` flag, CommonJS interop, barrel re-exports and dynamic access.

Q · I import one function from a large library. Why did the whole library end up in my bundle?
Bundle Analysis
▶ lab

Reading a treemap: attributing bytes to modules, finding the dependency nobody meant to add, and separating "large" from "large and on the critical path".

Q · The bundle grew. What is in it, who put it there, and does any of it matter to the user?
Minification Is Not Compression
▶ lab

Minification rewrites the artifact and is permanent. Compression encodes the response and is undone by the browser. They compose, they are configured in different places, and they are not alternatives.

Q · My build minifies and my server compresses. Are those the same optimisation done twice, or two different things?
ESM vs CommonJS
▶ lab

Static structure known before execution versus a runtime function call that returns an object — and why the first is what makes tree shaking and named-export analysis possible at all.

Q · Why does the module format of a dependency change what my bundler can do with it?
Polyfills vs Transpilation

Transpilation rewrites syntax an engine cannot parse. A polyfill supplies an API an engine does not have. Neither can do the other's job.

Q · The code works in my browser and throws in theirs. Do I need to transpile it, polyfill it, or neither?
Source Maps

The mapping from the bundle that shipped back to the source you wrote. Without one, a production stack trace names a minified letter on line 1.

Q · An error came in from production pointing at `t` in `app.4f2c.js:1:88214`. How do I find out what that is?
TypeScript in the Build

Parse, type check, emit. The types are erased before anything runs, so nothing they promised is enforced at the network boundary.

Q · The response is typed as `Order`. Why is `order.total` undefined at runtime?

Rendering Strategies

9 lessons

CSR, SSR, SSG, streaming SSR, islands and server components as points on a curve between where work happens and when the page becomes interactive.

Client-Side Rendering

The server sends a shell, the browser downloads a bundle, runs it, then asks for data. Everything a person can read sits behind that chain.

Q · What has to finish before a client-rendered page shows anything, and who is excluded while it waits?
Server-Side Rendering

The server fetches the data and renders the markup per request, so content arrives early. Interactivity does not arrive with it.

Q · What does rendering on the server actually move, and what does it leave exactly where it was?
Static Site Generation

Render every page once at build time and serve the files from an edge. The cheapest thing to serve, and the hardest thing to keep current.

Q · What does moving rendering to build time actually buy, and what does it make expensive?
Hydration

The client attaches behaviour and state to markup that already exists. Until it finishes, the page looks finished and is not.

Q · How does server-rendered HTML become an interactive application, and what is the page during the interval in between?
Hydration Mismatch

The client renders something different from what the server sent. The framework cannot quietly pick a winner, because it does not know which one is right.

Q · Why does the client disagree with the server-rendered markup, and why can the framework not just fix it?
Islands and Partial Hydration

Ship JavaScript only for the regions that are genuinely interactive. The saving is real; the cost is a component model that must declare its boundaries.

Q · Why is the whole page being hydrated when only three things on it do anything?
Streaming Server Rendering

Send the page in pieces as each part becomes ready. One slow region stops holding the whole document hostage — and once the first byte is out, you cannot take it back.

Q · Why should the server send an incomplete page, and what becomes harder once it has?
Server Components

Components that run only on the server and never ship. A framework-specific answer to "how much of this tree needs to be code in the browser at all".

Q · What changes when a component runs only on the server and its code never reaches the browser?
Choosing a Rendering Strategy

There is no winner. There are seven questions, and a real application usually answers them differently for different routes.

Q · Which rendering strategy should this route use, and what am I actually deciding when I pick one?

Frontend Testing

6 lessons

Choosing the level by what it can actually prove: pure logic, component behaviour, critical user flow, visual appearance, and the accessibility checks a tool cannot finish.

Choosing the Test Level

Pure logic, component behaviour, critical user flow, visual appearance and accessibility are five different observations. The level is chosen by what the failure would look like, not by a pyramid.

Q · Which kind of test would actually have caught this bug, and what is that kind of test structurally unable to see?
Testing Pure Logic

The cheapest, fastest and most reliable tests you will ever write — and the reason to get logic out of components so that it can be tested this way at all.

Q · Which parts of my frontend can be tested with no browser, no mounting and no waiting, and how do I get more of it there?
Component Testing

Given a rendered component, when the user interacts, then visible behaviour changes. Querying by role and accessible name is both better practice and an accessibility check you get for free.

Q · How do I test what a component does for a person, without testing how it happens to be implemented?
End-to-End Testing

A real browser over the flows you cannot ship broken — signup, login, checkout, payment, upload, critical navigation — and an honest account of what that costs.

Q · Which flows justify a real browser driving a real stack, and what will that suite cost me every week for the rest of the project?
Visual Regression Testing

The only level that observes what the browser painted — and a genuinely high-maintenance one, paid for in baselines and false positives from fonts, animation and dynamic content.

Q · How do I catch the breakages that no assertion describes, without drowning in image diffs that mean nothing?
Accessibility Testing

Automated rules catch a real but limited fraction of accessibility defects — and the ones they cannot decide are the ones that stop people using the product. Keyboard and screen-reader passes are not optional.

Q · What can an automated accessibility check actually decide, and what must a person still do by hand?

Frontend Observability

6 lessons

Errors, failed requests, vitals and interaction latency from real users on real devices — and the privacy obligations that come attached to every one of them.

Frontend Error Tracking
▶ lab

Capturing exceptions and unhandled rejections with enough context to act on — the route, the release, the breadcrumbs — and separating real signal from extensions, bots and opaque cross-origin noise.

Q · An exception was thrown in a browser I will never see, on a device I do not own — what has to reach me for it to be fixable?
Real User Monitoring
▶ lab

Field measurement from the machines your users actually own — how it differs from synthetic testing, why the two disagree, how to sample, and why watching the median hides the problem.

Q · My lab run is fast and support says the app is slow — which of the two is telling the truth about what people experience?
Vitals in the Field
▶ lab

Loading, interaction responsiveness and visual stability measured on real devices — what each observer actually records, why field values differ from lab values by design, and why the boundaries are not yours to memorise.

Q · What do the user-experience vitals actually measure, and why does the field value never match the one my build produced?
Network Failures Only the Client Can See
▶ lab

Requests that never arrived, timeouts, DNS and TLS failures, opaque CORS errors, offline users and navigations that cancel in flight — the failures with a zero server error rate.

Q · The server reports a clean error rate and users say the app is broken — where is the failure happening?
Session Replay and the Privacy It Costs
▶ lab

Replay records whatever was on the screen — including things you did not intend to record. Masking is opt-out shaped and fails open, so the governance question comes before the engineering one.

Q · Before recording a user's session, what exactly am I collecting, who is it about, and what happens when the masking is wrong?
Release Health
▶ lab

Attributing a regression to a deploy when clients update on their own schedule: tagging every signal with a release, reading the adoption curve, and comparing cohorts instead of time windows.

Q · Errors went up an hour after we deployed — was it the deploy, and how would I know?

Frontend Debugging

6 lessons

Reproduce, then work the layers: network, console, DOM and CSS, application state, performance, memory. A method, not a tour of a devtools panel.

A Method for Frontend Bugs
▶ lab

Reproduce, work the layers in order, narrow by bisection, fix, and then prove the signal moved. The method is the skill; the panels are interchangeable.

Q · How do I get from "it is broken for some users" to a fix I can show actually changed the thing that was broken?
A Mental Model of the Devtools
▶ lab

Seven panels, seven questions. Learn which question each one answers and what it structurally cannot tell you, and the UI can change underneath you without costing you anything.

Q · Which question does each devtools panel actually answer, and what is that panel incapable of telling me?
Debugging the Network
▶ lab

Read the waterfall for its shape, not its totals. Then learn the three ways the network panel lies: the CORS error that is a 500, the cache row that is not a hit, and the request that is missing because a service worker answered it.

Q · What did the browser actually request, in what order, what was each request waiting for, and where did the response really come from?
Debugging Rendering and Jank
▶ lab

Separate a frame that took too long from a frame that was never attempted, then find which pipeline stage the change is actually costing — with the forced-layout warning, paint flashing and layer borders as your three cheapest instruments.

Q · This feels janky — is the browser doing too much rendering work, or is something else holding the thread it renders on?
Debugging State
▶ lab

A wrong value on screen is the end of a sequence, not a snapshot. Reconstruct the transitions, then answer the question that resolves most of these bugs: which copy of this data is authoritative?

Q · The data on screen is wrong — which copy of it is authoritative, and what sequence of events produced the one I am looking at?
Debugging Memory
▶ lab

Three snapshots across a repeated cycle, then follow the retainer chain to whatever is holding the thing that should have gone. Growth is not a leak until you can say what is keeping it alive.

Q · Memory keeps climbing in this tab — is something leaking, or is a cache doing exactly what it was asked to do?

Frontend Architecture

7 lessons

MPA, SPA, SSR app, static site and micro frontends; design systems, internationalization, BFFs, deployment — and the fact that web clients never update atomically.

Choosing a Frontend Architecture

MPA, SPA, SSR application, static site and micro frontends compared on team shape, content versus application, discoverability, interactivity depth and deployment independence — with no universal winner.

Q · Given this product, this team and these users, which frontend architecture is the right one — and what actually decides it?
MPA vs SPA

An MPA gets history, scroll, focus reset, back and forward, and per-page code loading from the browser. A SPA must rebuild all of it — and buys preserved state and richer transitions in return.

Q · What exactly does the browser do for a multi-page application that a single-page application has to reimplement, and what does the SPA get in exchange?
Micro Frontends

Independently owned and deployed frontend boundaries. The driver is almost always organisational rather than technical, the benefit lands on teams, and the cost lands on users.

Q · When does splitting a frontend into independently deployed units pay for itself, and who actually pays the bill?
Design Systems

Tokens to components to patterns to applications: a versioned product with a public API, accessibility built in at the component layer, and an adoption problem that decides whether it is leverage or a cost centre.

Q · What is a design system actually made of, and what makes one that teams use rather than one that teams work around?
Design Tokens

Named values in three layers — primitive, semantic, component. The semantic layer is the one that makes a re-theme a set of value swaps instead of a rewrite.

Q · How should design values be named and layered so that a theme, a dark mode or a rebrand is a change to values rather than a change to every component?
Internationalization

Not a translation table bolted on later: plural rules, locale-aware formatting, text that grows, and a layout that has to work in both directions.

Q · What has to be true about this interface before it can exist in another language?
Timezones and Locale Formatting

Instant, timezone, locale, display — four separate things. Most date bugs come from collapsing them, and most of the rest come from string manipulation.

Q · This timestamp is correct in the database. Why is it showing the wrong day?

Production Frontend

7 lessons

Shipping to browsers you do not control: deployment, feature flags, analytics, uploads, the API contract you consume — and the fact that a web client never updates atomically.

Deploying a Frontend
▶ lab

Source to build to artifact to CDN to a browser you do not control — and the deploy that breaks the tabs already open.

Q · What actually happens between merging a change and a browser running it, and which step is the one that breaks people?
Long-Lived Clients and Version Skew
▶ lab

Production is running client v1, client v2 and backend v3 at the same time. There is no moment at which the frontend updates.

Q · If deploying does not update the tabs that are already open, what is actually running in production right now?
Feature Flags in the Client
▶ lab

Evaluating a flag in a browser: the three states every flag has, the flicker while it loads, the flagged-off code still sitting in the bundle, and the rule that a flag is never an authorization boundary.

Q · What changes when a feature flag is evaluated in a browser instead of on a server?
Analytics Events That Answer a Question
▶ lab

A named event with a stable schema answers a question. A firehose of clicks answers none — and carries personal data you did not mean to send.

Q · What should the frontend actually record about what people do, and what makes one event useful and another one noise?
File Upload UX
▶ lab

Progress, cancellation, retry, validation and preview — per file, not per form — plus the pre-signed URL that keeps a two-gigabyte video out of your application server.

Q · What does a browser actually have to do to move a file from someone's disk into your storage, and what must the interface show while it happens?
How API Shape Drives UI Complexity
▶ lab

Pagination style decides whether infinite scroll is even possible. Granularity decides whether a screen is one request or nine. The error model decides whether you can say anything useful when it fails.

Q · How much of my frontend complexity is actually a consequence of the shape of the API I was handed?
Backend for Frontend
▶ lab

A server the frontend team owns, sitting between the browser and several backend services. Why a client asks for one — and what the team signs up for by running it.

Q · When is a server owned by the frontend team the right answer, and what does that team take on by owning it?

Agentic Frontends

6 lessons

Streaming tokens, tool progress, citations, cancellation and partial failure — plus the rule that a model suggesting an action is never the same as the action being authorized.

What the Frontend Owns in an Agent Product
▶ lab

The model runs elsewhere. The client is a UI for an operation that streams, takes tools, fails halfway and must never be trusted with authority.

Q · Where does the frontend stop and the agent begin, and which of these problems are actually mine?
Streaming a Response Without Melting the Device
▶ lab

Tokens arrive dozens of times a second on a thread that also has to paint. What you do per chunk decides whether the answer feels alive or the page feels broken.

Q · How do I render an answer as it arrives without re-rendering the world on every token?
Showing What the System Is Doing

Observable states — searching, retrieving, calling, processing — reported honestly. Not a dramatisation of thinking the system cannot actually show you.

Q · What do I show during the thirty seconds when the model is not producing text?
Citations and Answers With Holes In

A source the user can actually check, and an answer that admits what it is missing. Both are interface problems before they are model problems.

Q · How do I render an answer so that a person can tell how much of it to trust?
Stopping It, and Trying Again Safely

Cancellation is two-sided and retry is not free: a run that already called a tool has already changed something.

Q · What does stop actually stop, and what is safe to do again?
A Suggestion Is Not an Authorization
▶ lab

The model proposes; structured validation, a permission check and the backend decide. The UI shows only what was actually confirmed.

Q · The model wants to do something. What has to be true before it happens, and what does the interface owe the user?