Skip to Content
Vektos
Anecdotes

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.

  1. 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 :invalid matches every empty required input. The name says "invalid", the selector says "the browser thinks so".
  2. The Select placeholder looked like a value. "Choose a currency" was the same color as a chosen currency. The style was _placeholderShown on the value text, but Ark (through Zag) sets data-placeholder-shown on 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.invalid in panda.config.ts, documented in guides/06-components.
  • It happened again, and axe caught it this time (journal chapter 29). accent.default is described as "readable as text on a surface" and is, at 4.85:1. The first underlined links put it on bg.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.

On this page