EdgeCases - Frontend Insights for Senior Engineers
"Experience is the name everyone gives to their mistakes."
Native CSS scoping with upper AND lower boundaries — finally, component isolation without Shadow DOM or naming conventions.
Combine timeout, user cancellation, and navigation signals into one — without race conditions or manual cleanup.
JavaScript's answer to RAII — automatic cleanup for file handles, locks, and event listeners that actually runs.
Code-split chunks racing against each other cause production-only crashes. Network latency turns microsecond races into user-facing errors.
Edge runtimes aren't Node.js. No fs, no native modules, no TCP sockets, and strict CPU limits. Know the constraints before you deploy.
NoInfer blocks type inference from specific positions. Use it when secondary parameters should match the inferred type, not influence it.
Your RSC streaming might be silently buffered by Nginx defaults—here's how to fix it
Explicit caching opt-in with 'use cache', cacheLife profiles, and tag-based revalidation
Why linear chat history fails for engineering—and how structured Artifacts provide the missing state layer
Wasm engine replaces Rust binary—90% smaller bundles and zero cold starts
Why transform is S-Tier and width is F-Tier—mastering the browser rendering pipeline
The difference isn't in policies—it's in the thousand small decisions that reveal whether remote is core or cosmetic
Canonical tags are hints, not directives—Google's ~40 signal algorithm may override your preference
JavaScript's Temporal API replaces Date, but brings new complexity. DST ambiguity, Plain vs Zoned types, and strict parsing will trip up migrating teams.
Container queries are here, but containment types and the ancestor lookup algorithm create subtle traps. Here's what breaks and how to fix it.
Auto-growing textareas and inputs without JavaScript—finally native in CSS. One property replaces ResizeObserver hacks.
Native CSS masonry finally replaces JavaScript grid libraries. grid-template-rows: masonry packs items into the shortest column—no JS, no layout thrashing.
Finally—style elements based on their position among siblings without JavaScript. Staggered animations, rainbow colors, and dynamic layouts in pure CSS.
balance equalizes headline line lengths. pretty prevents orphans in paragraphs. Both eliminate decades of typography hacks with pure CSS.
Master TypeScript's infer keyword for nested type extraction, variance-aware inference, and recursive unwrapping patterns.
AbortController isn't just for fetch—use it to cancel event listeners, timeouts, and any async operation with a single abort() call.
Animate elements appearing from display: none using @starting-style—pure CSS entry transitions without JavaScript timing hacks.
Declare custom property types with @property to unlock gradient, color, and numeric animations
How TypeScript infers +readonly and -optional in mapped types—and when inference silently breaks
Typed custom properties enable smooth interpolation but force main-thread animation—here's what to watch for
When React silently skips your re-render—Object.is, lanes, and the children-as-props escape hatch
The modern History API replacement that centralizes SPA routing into a single navigate event
Keys aren't just for warning suppression—they control whether React preserves or destroys component instances. Misuse causes invisible state bugs and performance problems.
Micro-frontends sharing React create subtle memory leaks when remotes update—old module closures retain references to shared singletons, preventing garbage collection.
rootMargin only expands the viewport—nested scroll containers clip your elements first. Use scrollMargin to fix lazy loading in carousels and scrollable regions.
IndexedDB transactions auto-commit when the event loop has no pending requests. One await in the wrong place, and your data is inconsistent.
Subgrid works everywhere now, but Chrome, Firefox, and Safari disagree on gaps, auto-sizing, and named lines. Here's what to watch for.
Functions, DOM nodes, and class prototypes can't survive postMessage. Here's exactly what fails, what works, and the zero-copy escape hatches.
The declarative popover attribute escapes z-index hell—until nested menus clash, light dismiss misfires, and focus management surprises you.
Errors inside Suspense don't always reach your ErrorBoundary. Master propagation rules, SSR behavior, and recovery patterns for resilient React apps.
Cross-document View Transitions enable native MPA animations, but 4-second timeouts, BFCache interactions, and name conflicts can break the magic.
Template literal types compose beautifully—until they explode. Understand instantiation depth, Cartesian products, and recursive limits to avoid TS2589.
skipWaiting() doesn't mean instant. clients.claim() has timing gotchas. First visits don't use your SW. Master the edge cases to build reliable PWAs.
React 18 batches all state updates automatically—unless you're using legacy render, flushSync, or hitting async boundaries. Know when batching breaks.
T extends U ? X : Y behaves completely differently when T is a union—TypeScript distributes the conditional over each member. Master this rule to unlock advanced utility types.
React 18 concurrent rendering can pause mid-render—if external stores change during that pause, components see inconsistent data. useSyncExternalStore prevents this 'tearing' problem.
Tell browsers 'this element is independent' with CSS contain. Layout, paint, and style calculations get scoped to the subtree—potentially cutting layout costs by 80%+.
z-index: 9999 still behind? Stacking contexts are the reason. Opacity, transform, filter, and 12+ other properties silently create them—trapping your elements.
Math.random() IDs break hydration—server and client generate different values. useId creates stable, deterministic IDs based on component tree position.
Finally select parents based on children. Use :has() for conditional styling, previous sibling selection, and patterns that previously required JavaScript.
Microtasks run when the JS stack empties, not just at task boundaries. This changes behavior with event bubbling, .click(), and recursive promises.
satisfies validates without widening. Unlike type annotations, it preserves literal types and enables better narrowing downstream.
CSS Anchor Positioning eliminates JavaScript tooltip libraries. One anchor-name, one position-anchor, and the browser handles collision detection.
Promise.withResolvers() eliminates the deferred promise hack, but leaked resolvers create memory leaks that are harder to spot than the old pattern.
structuredClone() handles circular refs and built-in types, but silently drops prototypes, class instances, getters, and Symbol properties.
The animation shorthand silently resets your scroll timeline. Plus: main thread demotion, inactive timelines, and stacking context surprises.
Normal layers: last wins. Important layers: FIRST wins. Learn why !important inverts layer priority.
Benign but scary. Learn why modifying layout in a ResizeObserver callback triggers browser loop protection.
Deeply nested recursive types crash the compiler—learn to optimize with interface caching and tail recursion
Skipping layout boosts performance but breaks scrollbars—use contain-intrinsic-size: auto to fix the jump
Fix the jagged edges and flickering lines on expanding images with outline: 1px transparent
Stop hacking refs—use the stable hook designed for non-reactive logic
Stop writing top/right/bottom/left—use inset to handle all four offsets in a single line
Don't just remove animations—replace motion with opacity to preserve context while respecting accessibility
Why border-radius sometimes leaves a gap between background and border, and how background-clip fixes it
Context fragmentation, multimodal gotchas, and agentic patterns at extreme scale
Antigravity's autonomous agents excel at large refactors but break debugging flow. Cursor's inline copilot preserves immediacy but can't parallelize. The edge cases reveal when each architecture dominates.
Cache pages, components, and functions with opt-in directive and stale-while-revalidate profiles
Rust-powered bundler with incremental compilation, file system caching, and production parity with Webpack
Full filesystem and npm package access in middleware—proxy.ts replaces middleware.ts with Node.js runtime
Layout deduplication, viewport-based cancellation, and interaction prioritization reduce redundant requests
Explicit caching with 'use cache', Turbopack as default bundler, and proxy.ts for Node.js runtime clarity
Figma's spring physics can't translate to CSS cubic-bezier—understand the gap between design and code
grid-template-columns won't animate—fr units lack computable intermediate values, breaking smooth transitions
JavaScript animations cause layout thrashing—learn CSS tricks and FLIP to keep animations compositor-safe
The more you know, the less confident you feel—why expertise breeds doubt and how to work with it
Streaming SSR sends HTML in chunks—but does Googlebot wait for the complete stream before indexing?
Schema.org validation passes, but Google Rich Results Test says 'No items detected'—here's why
loading=lazy on hero images delays LCP; WebP needs JPEG fallbacks—optimize without breaking SEO
Client-side navigation breaks traditional PageRank flow—hub-and-spoke vs mesh, the death of nofollow sculpting
Invisible bounding boxes in fonts cause alignment issues—learn to fix them with CSS overrides
font-display values force a choice between fast rendering and layout stability—understand the trade-offs
Match fallback font metrics to custom fonts and eliminate 90% of CLS from font loading
font-feature-settings doesn't cascade—it replaces. Learn the high-level font-variant-* alternatives
Missing crossorigin causes double downloads; too many preloads delay LCP—use surgically
Prevent browsers from creating fake font variants and ensure professional typography
Master custom typography with @font-face and variable fonts for better design flexibility