The blog

Writing from the workshop

202 articles on the parts that actually hurt.

section
Stop Hand-Rolling an Exclusive Accordion. `<details name>` Does It
HTML

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.

Oct 4, 2026 · 6 min
React 19.3 ViewTransition: Animate State Without Losing It
React

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.

Oct 3, 2026 · 15 min
Your Search Box Lags. Debounce Hides It; `useTransition` Fixes It
React

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.

Oct 3, 2026 · 5 min
NestJS 12: Standard Schema Validation Without class-validator
Nestjs

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.

Oct 2, 2026 · 14 min
Stop Fixing Headline Gaps With Negative Margins. Use `text-box-trim`
CSS

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.

Oct 2, 2026 · 5 min
`:nth-child(even)` Counts Hidden Rows. `of S` Fixes Your Stripes
CSS

: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.

Oct 1, 2026 · 4 min
Vue computed(): What It Caches and When It Reruns
Vue

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.

Sep 30, 2026 · 12 min
Your `backdrop-filter` Is Working. Your Background Is Hiding It.
CSS

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.

Sep 30, 2026 · 7 min
Why your code review comments sound harsher than you meant
The people around you

Why your code review comments sound harsher than you meant

A review comment loses your tone on the way, and the author fills it back in — usually with a worse one, at the exact moment they're most attached to the work. Here's how to put the weight back into what you write, the words to use, and when to stop typing.

Sep 30, 2026 · 8 min
Blocking `<script>` Won't Stop innerHTML XSS. `setHTML()` Will.
JavaScript

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.

Sep 30, 2026 · 7 min
Nuxt Server Routes Explained: How Nitro Builds Your API
Nuxt

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.

Sep 29, 2026 · 13 min
Your 'Save' Button Makes Copies. The File System Access API Doesn't.
JavaScript

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.

Sep 29, 2026 · 7 min