Page loaded: UI Architecture Notes for Angular Teams, Page 2

Writing

Notes on building, architecting, and maintaining front-end systems that no longer feel new.

I write about Angular, CSS, responsive design, accessibility, rendering, and long-lived UI decisions shaped by changing requirements, shifting teams, and real business pressure.

Miguel Carino
Focus
Front-end architecture, Angular, team leadership, and stakeholder communication
Experience
25+ years turning enterprise web complexity into maintainable products

CSS Grid That Replaced Half My Media Queries

The card wall had four breakpoints, and none of them knew how much space they actually had. One line of grid asked the container instead of guessing at the viewport.

A stack of breakpoint media queries reflowing a card grid came down to a single intrinsic grid declaration. The layout started responding to available space instead of to guesses about screen width. read more...

When Route Metadata Became Architecture

Every page set its own title in a lifecycle hook, and half of them forgot. The share cards came up blank, the tab titles all said 'App', and the fix wasn't more setTitle calls — it was moving metadata out of the components entirely.

Per-component title and meta calls scattered across a codebase became a routing concern: metadata declared as route data, applied in one place, rendered on the server so crawlers actually see it. read more...

One Service, Two Injectors

The new Angular component added an item to the cart. The old AngularJS view swore the cart was empty — because each framework had quietly built its own copy of the 'shared' service.

In an ngUpgrade hybrid, a service registered in both frameworks becomes two instances with diverging state. The fix is to give it one owner and bridge that single instance across the injector boundary. read more...

The JavaScript I Stopped Writing

A ResizeObserver to make a card respond to its own width. A click-outside handler for a menu. A watcher that toggled a class on a parent when a child changed. The platform grew a native answer for each one, and I deleted the scripts.

A lot of the JavaScript we wrote for layout and for reflecting state in the DOM is now a CSS or HTML feature. Container queries, :has(), the Popover API, cascade layers, and subgrid replace whole categories of glue code — with one that still needs a support caveat. read more...

The Preview Card That Never Filled In

Every link I shared previewed as the same generic card. The per-page title, description, and image existed — but only after JavaScript ran, and the crawlers reading the link never ran it.

On a statically hosted single-page app, whether a page is visible to search and social crawlers is decided at build time, not at runtime. Prerendering bakes the metadata into the HTML the crawlers actually read. read more...

The Store I Reached For and Didn't Need

The feature's state was small and lived in one place. I wrapped it in a global store with actions, reducers, and effects anyway — and wrote more code describing the state than the feature spent using it.

Defaulting to the heaviest state tool cost more than it returned. The real decision is matching the tool to the shape and reach of the state: component signals, a signal service, NgRx SignalStore, or classic NgRx. read more...

The Hydration Mismatch Only Some Users Saw

The server rendered one DOM, the browser rendered another, and Angular threw the server's away — but only for users whose first paint depended on something the server couldn't know.

A personalized greeting read from localStorage during the first render, so the client markup diverged from the server's and hydration tore down the DOM. The fix was keeping the first render platform-neutral and personalizing after hydration. read more...

Whose Job Is Cross-Field Validation?

A rule about two fields kept living on one of them — and broke every time the form's shape changed. The owner of a cross-field rule is the group, not a control.

An 'end date after start date' validator reached up through the parent to read a sibling control, and failed whenever the form was rebuilt. Typed forms and a group-level validator put the rule where it belongs. read more...

Two Copies of One Singleton

The shell logged the user in. The remote still thought they were a stranger — because 'shared' state wasn't actually shared.

A micro-frontend remote bundled its own copy of a service the shell also owned. Two instances, one name, diverging state. The fix was telling the federation boundary the truth about what must be singleton. read more...

The Focus Trap I Stopped Writing

I had hand-rolled the same modal focus management three times before I admitted the platform already owned it.

A custom modal kept leaking focus to the page behind it. The fix wasn't a better trap — it was handing the job to a native <dialog> and keeping only the two things the platform doesn't give you. read more...