Green checks, red border
Two styling bugs that passed tsc, lint and axe, and were caught only by looking at a screenshot.
Date: 2026-11-08. Context: building the eight components (feat/ds-components).
What happened
All 25 stories passed: tsc, oxlint with the Panda rules, and axe (WCAG A, AA and best
practices) in both themes, 50 runs, zero violations. Then two screenshots showed two bugs.
- The required field was red on load. In the transfer dialog, the empty
"Recipient" input had a red border before anyone typed. The input used
_invalid, and Panda's preset defines it as:is(:invalid, [data-invalid], [aria-invalid=true]). The native:invalidmatches every emptyrequiredinput. The name says "invalid", the selector says "the browser thinks so". - The Select placeholder looked like a value. "Choose a currency" was the same
color as a chosen currency. The style was
_placeholderShownon the value text, but Ark (through Zag) setsdata-placeholder-shownon the trigger, not on the text. The class was generated and applied, and matched nothing.
Fixes: redefine invalid in the config's conditions to the two data attributes, and
move _placeholderShown to the trigger. A comment explains each one in place.
What we learned
Both bugs used a real token and a real condition. Nothing was misspelled or invalid, so no static check could object. The first bug was a condition that does more than its name. The second was a condition aimed at the wrong element. In both cases the code reads correct, and the only proof of the mistake is the rendered pixels.
Axe did not help either. A red border is not an accessibility violation, and a placeholder at normal text contrast is more readable, not less.
What it means for Vektos
1. The graders measure adherence, not correctness. An agent that writes
_invalid: { borderColor: "danger.default" } uses the design system perfectly and still
ships a form that shouts at the user. Vektos should say so honestly in the results: a
clean score means "followed the system", not "looks right".
2. The design system can remove the trap. After the fix, _invalid in this config
means exactly what FormField says. Agents (and people) who trust the name are now
right. Every place where the system makes the obvious move correct is a place the
benchmark does not have to police.
3. Visual checks catch a different class of errors. This is the case for the visual diff in phase 2 (PLAN §7): a screenshot of a task's output, compared with a reference.
Follow-ups
- Done:
conditions.extend.invalidinpanda.config.ts, documented in guides/06-components. - It happened again, and axe caught it this time (journal chapter 29).
accent.defaultis described as "readable as text on a surface" and is, at 4.85:1. The first underlined links put it onbg.subtle, the table headers, where in dark mode it is 3.97:1. A real token on a background next to the one it was checked on. The fix is a token for the job:accent.text, checked on every background in both themes. - When the task runner exists, keep one screenshot per task result, even before a visual grader, so a human can spot this class of bug.
The token table that should not have used tokens
Four attempts to style a docs table with the design system, and why the fifth removed them all.
Twelve percent is not a style
The first grader would have punished agents for fintech data and missed real violations. What a grader counts is a design decision.