The review table
beginner·8 min·Markdown for agents
What this lesson teaches
Read and write a UI review as Before | After | Why rows, scan code against the checklist, and scope a review to what a change actually broke.
Here is a review you have probably received: "The animation could be smoother, the transition is a bit long, consider a different easing curve."
You read it twice. You still don't know what to type.
✕ Prose review
✓ Table review
transition: transform 0.6s ease → 0.25s cubic-bezier(0.25, 1, 0.5, 1). Under 300ms feels responsive.scale(0) → scale(0.95). Nothing real appears from nothing.Three columns, every time
The skill makes every UI review a table with three columns. Emil Kowalski calls this format non-negotiable, because it forces concrete diffs instead of advice.
| Column | What goes in it |
|---|---|
| Before | The real line from your code, quoted. Never paraphrased. |
| After | The replacement. Same job, better feel. |
| Why | One short sentence, ending with the skill node that goes deeper. |
If you can't write the Why in one sentence, you're probably reaching. Drop the row.
One issue per row
Three problems in one line of CSS get three rows.Order by impact
The thing that breaks keyboard users goes above the hairline.Nothing actionable in the prose
Prose around the table is context only: "Three issues in the modal entrance:".Nothing to fix is a valid review
"Looks good, nothing to change" beats invented nitpicks.
The checklist: a scan before taste
Before anyone argues about taste, there is a floor. The is thirty-nine common mistakes, each with a quick way to find it and a fix: transition: all, scale(0), ease-in on UI, a removed focus ring, z-index: 9999, 100vh on phones, placeholder names like "John Doe".
Edit the CSS below. Each rule is one of those quick checks; fix a line and its row disappears.
transition: all 300ms ease-in;transition: transform 200ms, opacity 200ms`all` animates layout properties too and janks. [[transform-opacity-only]]scale(0)scale(0.95); opacity: 0Nothing real appears from nothing. [[never-scale-from-zero]]ease-incubic-bezier(0.23, 1, 0.32, 1)ease-in starts slow, so UI feels hesitant. [[easing-curves]]no reduced-motion guard@media (prefers-reduced-motion: reduce) { … }Movement must honour the OS setting. [[prefers-reduced-motion]]z-index: 9999;z-index: var(--z-popover)Arbitrary z-index escalates forever. [[z-index-strategy]]outline: none;:focus-visible { outline: 2px solid; outline-offset: 2px }Keyboard users lose their place. [[accessibility-baseline]]Two warnings come with it. The checklist is a floor, not a ceiling: the best reviews catch what isn't on it. And it is a flag, not a law: a 500ms animation is fine on a rare celebration moment. Read the context before writing the row.
Review src/Modal.tsx as a Before | After | Why table. Scan it against the review checklist first. Quote my real lines in Before. End each Why with the node that owns it. Three to five rows, most important first. If nothing fails, say so.
Reviewing a change, not a codebase
Now picture a pull request: a set of changes you want merged. The author is asking one question: did I make this worse?
A review that answers "here is everything wrong with this codebase" buries the two lines that matter under thirty that don't. A answers the real question.
<div onClick={save}><button onClick={save}>The refactor turned a button into a div: no keyboard, no role.transition: all 300mstransition: transform 200msAnimate only what moves.z-index: 9999z-index: var(--z-popover)Not this change. Listed, not blocking.Resolve the scope
With no target named, the agent reviews the commits your branch has that main doesn't, plus anything uncommitted, and says how many of each. With nothing changed, it asks what to review instead of inventing a scope.
Follow the blast radius
A changed file is evidence, not the subject. Its is every screen that renders it. Change a token, and every component using that token is in scope.
Read the removed side
Regressions are invisible in the after state. A <button> that became a styled <div> in a "move to the new design system" refactor looks identical. Only the deleted lines show it.
So the agent searches the removed lines for signals that left: aria-*, <label>, :focus-visible, prefers-reduced-motion, a token swapped for a literal. Each is a lead, not a finding. aria-label replaced by aria-labelledby on visible text is fine; read the hunk before deciding.
Status by cause
Every finding gets a status, decided by what caused it, not by where it sits:
| Status | Means | Blocks the merge? |
|---|---|---|
| Introduced | the change created it | yes |
| Regression | the change weakened something that worked | yes |
| Pre-existing | it was already there, not made worse | no |
An untouched screen whose contrast now fails because a shared token changed is Introduced. A bug three lines from the edit that the edit didn't touch is Pre-existing. List at most three of those, plainly marked as not this change's job. Thirty is another review.
Review this branch as a change-scoped review. Scope: commits ahead of main plus uncommitted files; tell me how many. Read the removed lines for lost signals. Columns: Severity | Status | Location | Before | After | Why. Introduced and Regression only, then at most three Pre-existing.
Quick check
A pull request changes one shared color token. An untouched settings screen now fails contrast. What status does that finding get?
In the skill
The nodes your agent reads when it does this work.
- Review format (required)Mandatory format for UI code reviews — Before | After | Why markdown table.
meta/review-format - Review checklistAudit table — thirty-nine common UI issues, each with a grep and a fix. Scan against this before signing off.
meta/review-checklist - Change-scoped reviewReviewing a diff, not a screen. Resolve the scope (commits ahead of the merge base plus uncommitted work), expand changed files to the surfaces they render in, read the removed side of every hunk for lost signals, and status each finding Introduced, Regression or Pre-existing by cause, not by location. Only the first two block; three pre-existing findings is a courtesy, thirty is another review.
meta/change-scoped-review
Connected lessons
What this lesson builds on and leads to, across every course.