The inputs were accessible, but Form was only styling
/setupCaptured at a 375px viewport. Long pages scroll inside the frame.
The screenshots stay in Japanese. Every round is a real screen for a real Japanese industry, so an English re-render would no longer be the screen the agent actually produced.
Write-up
The inputs were accessible, but Form was only styling
Build log series: I hand a real screen to an AI that has never seen Gunjo (
@gunjo/ui) and let it build. This round covered a multistep setup wizard with validation and a review step.
I kept the source private and supplied the shipped npm package plus docs site. The assignment was a four-step "Create workspace" flow: Account, Organization, Settings, and Review. The Next button had to validate required fields and formats, stop progression, show inline errors, and focus the first invalid field. The review step had to jump back to editing, require agreement to the terms, and then submit. This was the first deep test of form validation as a system.
Result: 3.5/5
The validated four-step wizard worked end to end. It focused the first error, linked aria-invalid to the visible message, announced each step, fit at 375px, and dark mode worked throughout. The individual inputs were polished and reasonably accessible.
A fix from the previous round was verified again:
The
labelanddescriptionAPIs onCheckboxfrom issue #149 andSwitchfrom issue #130 are genuinely good. They generate IDs and wire up ARIA internally.RadioGrouphas proper standard accessibility, andInputautomatically shows an error border witharia-invalid.
The score stopped at 3.5 not because those controls were poor, but because Gunjo had no form system connecting them.
The central gap: Form was presentational only
Form, FormField, and FormMessage promised behavior their implementations did not provide (issue #152, major). They shared no state, managed no field state, and wired no ARIA. FormMessage was a plain <p class="text-destructive"> with no ID, field association, or role. The names suggested the shadcn and react-hook-form FormField pattern, but the behavior was absent.
The agent therefore hand-rolled about 90 lines for every field's coordination: generating IDs, composing aria-describedby, toggling aria-invalid, adding required markers and role="alert", and focusing the first error. Gunjo had accessible individual inputs but no layer that coordinated each label, control, description, and error. That was the missing form system.
What I fixed this round in the source
I made error presentation consistent and repaired Combobox accessibility:
- Issue #153: I extended the
aria-invalid:error border fromInputto Select,Textarea, andPasswordInput. PasswordInputhad a real defect:classNameapplied to its wrapper rather than the input, soaria-invalidproduced no red border. I moved the class to the input and addedinputClassName. A browser check measured thearia-invalidborder asrgb(252, 176, 176), the error color. - Issue #155:
Comboboxdid not acceptaria-invalidoraria-describedbybecause it failed to pass through HTML attributes. I forwarded them to the trigger, making required comboboxes show an error state. - Issue #156:
Textareahad a fixedw-[280px], another fixed-dimension defect. The style specification locked it, so the.pen(the design-source files) change went into the Codex handoff (the implementation queue).
The central form system in issue #152 required substantial shared state in FormField, so it went to the beta gate.
What I took away: accessible controls and a form system are different things
Present: individually accessible controls (Input, Checkbox, Switch, and RadioGroup) plus error tones and styling
Missing: a form system that coordinates IDs, ARIA, error state, validation, and focus across those controls
The individual components were good. The missing piece was the coordination layer. It matched the selectable collection in #28 and scheduler rendering layer in #27: strong components underneath, with no higher-level component to organize them. The gap was clearest in Form because its name already promised that behavior.
Next up: build log #30
- An error page, notification and toast flow, or dashboard settings screen.
The run
Gunjo was still in early alpha at the time; issues are welcome.
This series is co-created with AI (Claude and Codex). A human designs the experiments, makes the calls, and fact-checks before publishing; the AI does the hands-on work and drafting.
Components from @gunjo/ui
The components this screen's source imports directly.
The code the agent actually wrote
Click a file to expand its source.