Skip to Content
Vektos
Anecdotes

The class that did not win

A design-system button could not be changed with a class. Two Panda classes for the same property both stayed on the element, and the wrong one won. Nothing in the toolchain can see it.

Date: 2026-11-09. Context: building the chat page (feat/chat).

What happened

The chat has three starter questions, shown as outline Buttons. On a phone the longest one ran past the edge of its card. The cause was clear: the design system's Button is white-space: nowrap.

The fix looked trivial. Button takes a className, so I passed one:

<Button className={css({ whiteSpace: "normal", h: "auto", py: "2" })}>…</Button>

It type-checked, the linter and the benchmark's graders found nothing (the values are tokens), and the page did not change. In the browser the button's class list held both white-space_nowrap (from the component) and white-space_normal (from my css()), and the computed style was nowrap.

The component joins its classes with cx(buttonRecipe(...), className). Panda's cx concatenates class names; it does not merge them. Panda's styles are atomic, one class per property and value, and when two classes set the same property the one that comes later in the stylesheet wins, which has nothing to do with which one was passed last. Only css() merges, and only inside one call.

What we learned

  • An override can fail without an error, anywhere. The compiler sees a valid className. The linter sees a valid token. The graders see a valid style value. The page is the only place where the override is visibly not applied, and only to someone who looks.
  • This is how an agent will hit it. "Make this button wrap" is exactly what an agent given a design system will try, with exactly this line. It will write a clean, token-correct override that does nothing, and may then pile on more (!important, a wrapper, an inline style) to make it work. Those are the mistakes the graders do count, caused by one the toolchain cannot see.
  • The design system could have prevented it. A component that merges its recipe and the caller's className with css(recipe, className)-style merging (Panda's cx with css objects, or a css prop) lets a caller override. Or it can refuse: say plainly that it does not take overrides. Silently ignoring one is the worst of the three.
  • I did not fight it. The starter buttons now have short labels that fit, and send the full question when clicked. Working with the component, not against it, is what the system asks of an agent too.

What it means for Vektos

It belongs with anecdote 09: the second time a class that looked right had no effect on the page. Both are invisible to every static check and visible in a browser. The page checks of the benchmark (render, accessibility in two themes) catch a page that breaks, not one whose override was ignored; a visual diff against a reference page would, and it is on the list of things that need a pinned browser (guide 11).

Follow-ups

  • Decide what the design system's components do with a className that sets a property their recipe already sets. Done in chapter 35: they refuse it. The components are governed, take no className, and say so in the MCP's component help (guide 06).
  • A grader for className={css({…})} on a design-system component. Done in chapter 35: outside-styling counts it as a design-system violation (guide 03).
  • Try it on the benchmark: give a task that needs a button to wrap, and see what each model does.

On this page