Check what you actually know
93 quizzes. Every answer explained as you go, with a reference — and no account needed.

Stop Writing JavaScript to Open Dialogs. commandfor Fixes It.
Every <dialog> and popover in your app still needs an addEventListener just to open and close — commandfor and the Invoker Commands API let the browser do it with zero JavaScript.
Take the quiz →
Stop Shipping Search Boxes With a Race Condition
Type fast into a search box wired to fetch(), and the result on screen isn't from your last keystroke — it's from whichever request happened to finish last. That's a race condition, and the fix is a one-line guard.
Take the quiz →
You're Blocking Scroll by Default. passive: true Fixes It.
Every touch and wheel listener you add can make the browser wait before it scrolls — because it has to check whether you'll call preventDefault(). `passive: true` tells it you won't, and scrolling stops waiting on your code.
Take the quiz →
NestJS 12.2: Why validationError.target Is Now undefined
NestJS 12.2 defaults validationError.target to false, so a custom exceptionFactory reading error.target now gets undefined. The fix, plus a cheat sheet.
Take the quiz →
Stop Hacking Base64 With btoa(). toBase64() Fixes It Natively.
btoa() throws on emoji, and the classic String.fromCharCode(...bytes) workaround crashes on large files. toBase64() and fromBase64() on Uint8Array fix both — no string round trip, no library.
Take the quiz →
getCurrentPosition() Has No Default Timeout. That's the Trap.
A "find my location" button that works instantly on your laptop and hangs forever on a phone with a weak signal isn't flaky — it's getCurrentPosition() doing exactly what its defaults tell it to do. No timeout, no cached position, and a watcher nobody told to stop.
Take the quiz →
Your Canvas Is Freezing the Page. OffscreenCanvas Fixes That.
Click a button while your canvas animation is running and the whole page stalls — because the pixels it draws, your layout, and your input handling all queue up on the same main thread. OffscreenCanvas moves the drawing itself into a worker, so the UI keeps responding no matter how much canvas work is happening.
Take the quiz →
Next.js 16.4 ensureStatic: Locking Routes Fully Static
Next.js 16.4 stabilizes ensureStatic: lock a route's shell, prefetch, or full navigation to static output at build time, with a copy-paste cheat sheet.
Take the quiz →
React Activity Component: The State Between Render and Remount
React's Activity component hides a subtree without unmounting it — what state, effects, and renders actually do, plus a copy-paste cheat sheet.
Take the quiz →
Vue provide/inject: Why You Should Never Skip readonly()
Vue's guide says wrap provide() state in readonly() — most tutorials skip it. The mutation bug that causes, verified against Vue 3.5, plus a cheat sheet.
Take the quiz →
I Deleted My Scroll-Lock Library's Ugly Hack. scrollbar-gutter Replaces It.
Opening a modal shifts your whole page sideways because the scrollbar vanishes with it — the bug every scroll-lock library papers over with a JS width measurement and a padding-right hack. `scrollbar-gutter: stable` fixes it in one line now that Safari finally caught up.
Take the quiz →
Stop Hardcoding Color Variants. Relative Color Syntax Does It.
A design system ships one brand color and four hand-picked hex variants for hover, pressed, border, and tint. Change the brand color and four of those five silently go stale. CSS relative color syntax derives every variant from the one color you actually update.
Take the quiz →
You're Writing Mouse and Touch Handlers. Pointer Events Does Both.
A draggable card that works with mousedown/mousemove on desktop and breaks the moment you test it on a phone. The fix isn't a second set of touch listeners — it's deleting the mouse ones and switching to Pointer Events, which was built to handle mouse, touch, and pen as one input.
Take the quiz →
NestJS 12: @Optional() Not Inherited by a Redeclared Constructor
NestJS 12 stops inheriting @Optional() once a subclass redeclares its own constructor — not when it has none at all. Cheat sheet included.
Take the quiz →
Stop Using a JS Masonry Library. CSS Grid Lanes Does It Natively.
Masonry layouts have meant a JS library or a CSS column-count hack that scrambles reading order ever since Pinterest made the look popular. CSS Grid Lanes finally does it natively — here's the real support story and how to ship it today.
Take the quiz →
font-display: swap Fixes Invisible Text. It Also Shifts Your Layout.
Setting font-display: swap kills the flash of invisible text, so most teams call the font-loading problem solved and move on. It doesn't — it just trades FOIT for a layout shift Lighthouse will happily dock you for. Here's the actual fix.
Take the quiz →
Stop Calling form.submit(). Use requestSubmit() Instead.
A Save button living outside the <form> tag, wired to form.submit(), looks like it works — until a blank required field sails through and the page does a full reload your fetch handler never saw coming. requestSubmit() is the method that actually clicks the button for you.
Take the quiz →
Next.js 16 updateTag vs revalidateTag: What Changed
Next.js 16 deprecated revalidateTag's single-argument call and added updateTag. What the new profile argument changes, plus a copy-paste cheat sheet.
Take the quiz →
Stop Writing JS to Detect a Stuck Header. scroll-state() Fixes It.
A sticky header that should only cast a shadow once it's actually stuck to the top usually means a hidden sentinel div and an IntersectionObserver. CSS now tracks that state itself — the `scroll-state()` container query reads it directly, no sentinel, no observer, no JS math.
Take the quiz →
Vue v-for: The Directive Unmounted Hook Bug, Fixed in 3.5.41
A custom directive's unmounted hook could silently skip firing inside a keyed v-for list. The directive unmounted hook bug, Vue's real fix, and a cheat sheet.
Take the quiz →
You're Debouncing Scroll Wrong. requestAnimationFrame Fixes It.
Debouncing a scroll handler makes it wait until scrolling stops — which is why your sticky header always lags half a beat. requestAnimationFrame fixes the lag by syncing updates to the browser's own paint clock instead of a timer.
Take the quiz →
My Reducer's Switch Stopped Being Exhaustive. as const Fixed It.
Object and array literals widen to `string` and `number` the moment you write them, which quietly breaks discriminated unions and exhaustive switch checks. `as const` keeps the literal types — but it also freezes the value, which bites in its own way.
Take the quiz →
Nuxt 4.6 nuxt/server: Why Mixing h3 Imports Throws NUXT_E8012
Nuxt 4.6 added a new nuxt/server import source alongside h3 — mix the two in one handler and you hit NUXT_E8012. The real boundary, plus a cheat sheet.
Take the quiz →
Your Custom Hooks Tear in React 18. useSyncExternalStore Fixes It.
A useState + useEffect hook that subscribes to window size, localStorage, or a WebSocket looks fine until React 18's concurrent rendering shows two parts of your UI two different values at once. useSyncExternalStore is the hook built to stop that.
Take the quiz →
NestJS 12 Lifecycle Hooks: The Order You Can't Assume
NestJS 12 changed how lifecycle hooks are ordered. Learn what onModuleInit and onApplicationBootstrap really guarantee, plus a copy-paste cheat sheet.
Take the quiz →
Stop Jamming Translate, Rotate, and Scale Into One transform
A CSS :hover scale and a JS drag handler both write to `transform` — and the moment JS sets it, the hover rule silently stops working, no error, no warning. The `translate`, `rotate`, and `scale` properties exist so this never happens.
Take the quiz →
You're Letting the Browser Guess. fetchpriority Fixes That.
Your hero image is losing a bandwidth fight against a web font and a chat-widget script — fetchpriority tells the browser which request actually matters first.
Take the quiz →
Next.js 16.3 Instant Navigations: How Partial Prefetching Works
Next.js 16.3 shipped Instant Navigations: Partial Prefetching plus the App Shell. Learn the model, the Suspense gotcha, and a copy-paste cheat sheet.
Take the quiz →
Stop Formatting Currency With Regex. Intl.NumberFormat Does It.
A hand-rolled formatMoney() with toFixed() and a comma regex looks fine in a US demo and quietly breaks the moment a real user, a negative balance, or a non-dollar locale shows up. Intl.NumberFormat has handled all of it, built into every modern browser, since before most teams' codebases existed.
Take the quiz →
Vue 3.6: When a Watcher Throws, Your Other Watchers Stall
A Vue 3.6 reactivity regression let a throwing watcher silently stall its siblings. The exact flush() mechanism, the fix, and a copy-paste cheat sheet.
Take the quiz →
Your 'Expand All' Button Is Quietly Causing Layout Thrashing
An 'expand all' click that stutters isn't a slow CPU — it's layout thrashing, a loop that forces the browser to recalculate layout once per row instead of once per click. Here's how to spot it and the two-line fix.
Take the quiz →
Nuxt 4.6 useSession: Server Sessions Without a Database
Nuxt 4.6 ships useSession and runtimeConfig.appSecret — real, sealed-cookie sessions with no database or session store. How it works, plus a cheat sheet.
Take the quiz →
Stop Shipping Custom UI That Disappears in forced-colors Mode
Windows High Contrast Mode doesn't just boost contrast — it strips your backgrounds, shadows, and colors outright. Here's what `forced-colors` actually does, why a styled <div> vanishes while a real <button> survives, and the fix.
Take the quiz →
React 19.2 useEffectEvent: Why It Won't Fix Your Deps Array
React's useEffectEvent (stable in 19.2) kills stale closures in Effects without a ref trick — but it's not a deps-array shortcut. Guide + cheat sheet.
Take the quiz →
Inferred Type Predicates Won't Save filter(Boolean). Here's What Will.
TypeScript 5.5 added inferred type predicates, and the internet decided that meant filter(Boolean) finally narrows. It doesn't. Here's exactly what the feature fixed, why the mix-up happened, and the one-line pattern that actually gets you type-safe filtering.
Take the quiz →
Stop Letting One Widget Reflow the Whole Page. contain Scopes It.
A live counter or chat widget shouldn't make the rest of your page recompute layout every time it updates. The CSS contain property draws a hard boundary the browser can actually trust — here's what it promises, and the one gotcha that breaks pages when people misuse it.
Take the quiz →
Stop Electing a Leader Tab. SharedWorker Just Holds the Connection.
Electing a leader tab to own one shared WebSocket works great — until the leader is the tab someone closes. SharedWorker skips the election: the connection lives in the worker, not in any tab, so there's no leader to lose.
Take the quiz →
You Installed a Library for Numbers PerformanceObserver Already Has.
The web-vitals npm package gets credit for data your browser already computes. Here's what three PerformanceObserver calls give you for free — and the one piece of math it quietly saves you from getting wrong.
Take the quiz →
Your Tabs Each Open Their Own WebSocket. navigator.locks Elects One.
Six open tabs means six live connections to your server, six duplicate pushes, six timers draining the battery. navigator.locks elects a single leader tab to hold the real connection — the rest just listen.
Take the quiz →
Next.js 16 Image: priority Deprecated, quality Now Allowlisted
Next.js 16 quietly deprecated Image's priority for preload and restricts quality to an allowlist (default: 75). What breaks, plus a copy-paste cheat sheet.
Take the quiz →
Vue watch vs watchEffect: The Complete Guide
Vue's watch() and watchEffect() look interchangeable but track dependencies, run timing, and cleanup differently. The exact rules, verified against Vue 3.5.
Take the quiz →
I Shipped a Fix. My Service Worker Kept Serving the Bug.
A critical bug fix went out, and support tickets kept coming in from people who swore they'd refreshed. The code was fine. The service worker's cache-first strategy was doing its job perfectly — which was the whole problem.
Take the quiz →
Nuxt 4 Migration: The Breaking Changes That Actually Bite
Nuxt 3 reached end-of-life on July 31, 2026. Here's exactly what breaks moving to Nuxt 4 — directories, data fetching, TypeScript — plus a cheat sheet.
Take the quiz →
Your Lighthouse Score Is 100. Long Animation Frames Explain the Jank.
Lighthouse says 100 and CI is green, but a user still says the filter button feels sluggish. The Long Animation Frames API names the exact script and phase that blocked the frame — here's how to read it instead of squinting at a flame chart.
Take the quiz →
React 19.3 Fragment Refs: Skip the Wrapper Div for a Ref
React 19.3 Fragment Refs let you ref a sibling group with no wrapper div. Learn the FragmentInstance API, its limits, and get a copy-paste cheat sheet.
Take the quiz →
You Added will-change to Fix the Jank. You Made It Worse.
will-change: transform looks like a free performance switch. Applied broadly or left on permanently, it does the opposite — here's the narrow, temporary pattern that actually works.
Take the quiz →
You're Animating for Everyone. prefers-reduced-motion Fixes That.
Most animated UIs never check whether the visitor asked for less motion. `prefers-reduced-motion` is the CSS media feature that tells you — and a fail-closed pattern keeps you honest even when a browser doesn't support it.
Take the quiz →
Stop Losing Promise Errors. unhandledrejection Catches Them.
A rejected promise with no .catch doesn't crash and doesn't show up in your error tracker — it just disappears. The unhandledrejection event is the global safety net most apps never wire up.
Take the quiz →
Stop Retrying Immediately. Exponential Backoff Fixes It.
Retrying a failed fetch() right away feels responsible — until the server that failed was already overloaded, and five instant retries per client turn a blip into an outage. Exponential backoff with jitter is the fix.
Take the quiz →
I Built Cross-Tab Logout. The storage Event Skipped One Tab.
A cross-tab 'log out everywhere' feature built on the storage event worked in every tab except the one the user actually clicked in. The storage event never fires in the tab that made the change — and that's spec, not a bug.
Take the quiz →
Next.js Streaming Metadata: Why Your <head> Looks Incomplete
Next.js 16 streaming metadata sends users a page before generateMetadata resolves, but blocks crawlers for a complete head. How it works, plus a cheat sheet.
Take the quiz →
Vue defineModel: The v-model Contract, Explained
Vue's defineModel macro replaces the modelValue prop and update:modelValue event with one ref. The exact v-model contract behind it, verified against Vue 3.5.
Take the quiz →
beforeunload Can Still Kill Your bfcache. Mount It Only When Dirty.
A `beforeunload` listener you left mounted forever can still quietly cost you bfcache eligibility — and an `unload` listener reliably will. Here's the pagehide/pageshow fix, and why 'mount it only when there's something to lose' is the durable rule.
Take the quiz →
Nuxt 4.5 SSR Streaming: The Route Rules That Disable It
Nuxt 4.5's experimental SSR streaming flushes HTML early, but cache, isr, swr, redirect, and ssr:false route rules silently fall back to buffering. Cheat sheet included.
Take the quiz →
Stop Hand-Rolling an Exclusive Accordion. <details name> Does It
You've probably shipped an accordion with a hand-rolled 'close the other panels' loop in JavaScript. The `name` attribute on <details> does it natively — no JS, no ARIA plumbing.
Take the quiz →
React 19.3 ViewTransition: Animate State Without Losing It
React 19.3's ViewTransition component animates state changes, not just page swaps — the mental model, enter/exit/update/share, and a cheat sheet.
Take the quiz →
Your Search Box Lags. Debounce Hides It; useTransition Fixes It
A big list re-render was blocking every keystroke — debouncing just moved the freeze. useTransition tells React which update can wait.
Take the quiz →
NestJS 12: Standard Schema Validation Without class-validator
NestJS 12 adds Standard Schema validation for @Body(), @Query(), and @Param() — validate with Zod or Valibot, no class-validator DTO. Cheat sheet included.
Take the quiz →
Stop Fixing Headline Gaps With Negative Margins. Use text-box-trim
Line-height reserves space for accent marks your headline never uses — a hand-tuned negative margin only fixes it for one font at one size. text-box-trim does, natively, from the font's own metrics.
Take the quiz →
:nth-child(even) Counts Hidden Rows. of S Fixes Your Stripes
nth-child(even) counts every element in the DOM, including the ones you just hid with display:none. The fix isn't JavaScript — it's a CSS selector most people have never had a reason to use.
Take the quiz →
Vue computed(): What It Caches and When It Reruns
Vue's computed() caches its result and only reruns when a tracked dependency changes, not on every read. The exact caching and invalidation model, verified against Vue 3.5.
Take the quiz →
Your backdrop-filter Is Working. Your Background Is Hiding It.
backdrop-filter looks like a one-line copy from a Codepen: blur(20px), ship the frosted navbar. Half the time it renders as a plain flat panel instead — because backdrop-filter blurs whatever is BEHIND an element, and that only shows up if the element itself is see-through. Here's the transparency rule, the stacking-context trap it quietly sets, and why it's one of the priciest effects you can scroll past.
Take the quiz →
Blocking <script> Won't Stop innerHTML XSS. setHTML() Will.
A regex that strips <script> tags misses the XSS that actually runs — an onerror attribute. Element.setHTML(), from the HTML Sanitizer API, strips it natively, and for once Firefox shipped the finished version before Chrome did.
Take the quiz →
Nuxt Server Routes Explained: How Nitro Builds Your API
Nuxt server routes turn server/api into a real backend via Nitro and h3. Learn routing rules, defineEventHandler, middleware order, and the useState trap.
Take the quiz →
Your 'Save' Button Makes Copies. The File System Access API Doesn't.
The classic web 'save' — a Blob and an <a download> link — doesn't overwrite a file, it manufactures a new one every time, leaving notes.md, notes (1).md, notes (2).md scattered in Downloads. The File System Access API fixes this with real, permissioned read-write access to a file on disk. Here's the difference, and why it's Chromium-only progressive enhancement, not a drop-in replacement.
Take the quiz →
Stop Guessing When Scrolling Stops — Use scrollend
For years, 'has the user stopped scrolling?' was a guess: debounce the scroll event, pick a delay, hope. The scrollend event answers the question directly — and as of Safari 26.2, it finally works everywhere. Here's the bug the guess causes, and the one-line fix.
Take the quiz →
Next.js Route Handlers: GET Stopped Caching in 15 — How to Cache in 16
Next.js 15 made GET Route Handlers dynamic by default. What that changes for code written for 14, how to cache one on purpose in 16, plus a cheat sheet.
Take the quiz →
getCurrentPosition() Doesn't Just Check — It Prompts
You want to peek at whether location access is already granted before showing your own 'why we need this' banner. Calling getCurrentPosition() to find out fires the real system prompt. navigator.permissions.query() reads the state without ever asking.
Take the quiz →
NestJS Guards: CanActivate, ExecutionContext & Reflector
A complete guide to NestJS guards: how CanActivate, ExecutionContext, and the Reflector decide who reaches your route handler, with a cheat sheet.
Take the quiz →
localStorage Isn't Free — It's Blocking Your Main Thread
Autosave into localStorage looks harmless right up until the draft gets big. The API is synchronous by spec, so every write freezes the page for exactly as long as it takes — and debouncing doesn't fix it. IndexedDB does.
Take the quiz →
JSON.stringify Is Quietly Deleting Your File Uploads
An avatar upload form that passes every test, ships to production, returns 200 OK — and never actually uploads the picture. The bug is one function call that silently turns a File into an empty object, with no error anywhere.
Take the quiz →
The Background Task That Waited 40 Seconds for 'Idle'
requestIdleCallback promises to run only when the browser has spare cycles — but on a page that's never truly idle, that promise has no upper bound. Here's why the callback can stall, why the timeout escape hatch has its own trap, and when to reach for it instead of setTimeout or scheduler.yield.
Take the quiz →
Vue Composables: The Shared State Trap (+ Cheat Sheet)
Why two Vue components using the same composable can end up sharing state by accident, the mental model that explains it, and how to fix or embrace it.
Take the quiz →
The Dropdown You've Been Faking for a Decade
Every hand-built 'custom select' with icons and a styled popup exists because the real <select> couldn't do that. appearance: base-select just closed the gap — without you losing the native picker's keyboard nav and mobile UI.
Take the quiz →
Next.js proxy.ts Explained (with Cheat Sheet)
Next.js 16 renamed middleware.ts to proxy.ts and locked it to the Node.js runtime. Learn the network-boundary model, matcher config, and the migration path.
Take the quiz →
Stop Writing JavaScript To Fix 100vh On Mobile
Your full-screen hero looks perfect in the simulator and cuts off the CTA on a real phone. It's not a bug in your code — it's `vh` answering a question you didn't ask. Three new units fix it with zero JavaScript.
Take the quiz →
React Derived State: Why That useState Is Probably a Bug
React derived state explained: why syncing a computed value into useState with an Effect causes extra renders and drift, and what to write instead.
Take the quiz →
Your Browser Is Rejecting Every Drop On Purpose
A drop zone with a correctly wired drop listener that never fires — no error, no typo, nothing in the console. The browser is silently refusing the drop by design, and only one specific line stops it.
Take the quiz →
Nuxt Hydration Mismatch: Why It Happens and How to Fix It
A Nuxt hydration mismatch happens when the server's HTML disagrees with the client's first render. Learn why, and the fixes that actually work.
Take the quiz →
Chrome Already Has The Eyedropper You're Building
You're about to build a canvas-based color picker with a magnifier loupe. Chrome shipped a native one years ago — and it can sample pixels your own canvas can't even see.
Take the quiz →
NestJS Testing Module: Provider Overrides (with Cheat Sheet)
A complete guide to NestJS's testing module: how overrideProvider really wires mocks, why get() fails on scoped providers, and using useMocker.
Take the quiz →
The CSS Property That Fixes Dark Mode's Ugly White Boxes
You shipped dark mode. The page is black, the text is white — and then the date picker opens like a floodlight. color-scheme is the one-line CSS property that tells the browser your native form controls need to catch up too.
Take the quiz →
Stop Debouncing Resize. The Browser Already Watches It.
A debounced resize handler comparing window.innerWidth to a magic number can't ever see dark mode or reduced motion — and it fires dozens of times for one thing matchMedia fires once for.
Take the quiz →
Your Fetch Already Streams. You're Buffering It Anyway.
A chat UI that types out its reply letter by letter isn't proof it's streaming — it's often proof the opposite. fetch() delivers a real ReadableStream body, and most code drains it into one string before showing a single character.
Take the quiz →
Next.js Parallel & Intercepting Routes: Modals Done Right
How Next.js parallel routes (@slot) and intercepting routes ((.), (..), (...)) combine to build shareable, refreshable modals — verified against Next.js 16.3.
Take the quiz →
Your Custom Element Is Missing From FormData — ElementInternals Fixes It
A custom <star-rating> element sits inside a <form>, looks like a form field, and gets left out of the submission entirely. The browser has a real fix for this — most teams reach for a hack instead.
Take the quiz →
Vue nextTick Explained: How DOM Updates Are Batched
How Vue batches reactive writes into one DOM update, why the DOM looks stale right after a change, and how nextTick and watch's flush option fix it.
Take the quiz →
The 'Read Aloud' Button That Only Works on the Second Click
A text-to-speech button that works perfectly every time you test it — and silently fails or picks the wrong voice for a real visitor's first click. The bug is a timing race baked into the Web Speech API that most code never accounts for.
Take the quiz →
useAsyncData Keys in Nuxt: Caching, Dedupe & the Sharing Bug
Learn how Nuxt's useAsyncData and useFetch generate cache keys, how dedupe (cancel vs defer) really works, and why wrapper composables silently share data.
Take the quiz →
The Search Highlight That Deletes Your Selection
A search-highlight feature that rebuilds its DOM on every keystroke can wipe out a user's own text selection with no warning. The CSS Custom Highlight API fixes it by styling text ranges without ever touching a DOM node.
Take the quiz →
My .catch() Never Ran. The Bug Was Two Lines Above It
A function that sometimes throws synchronously instead of returning a promise will skip every .catch() chained to it — because the promise never gets created. Promise.try() fixes it, and does one thing try/catch can't.
Take the quiz →
NestJS Module Encapsulation Explained (with Cheat Sheet)
How NestJS module boundaries actually work: what exports really cross, why @Global() isn't a shortcut, and how forwardRef breaks circular module dependencies.
Take the quiz →
NestJS Dependency Injection Explained (with Cheat Sheet)
How the NestJS DI container resolves providers: tokens, module scope, singleton vs request vs transient, and why 'singleton' can still mean two instances.
Take the quiz →