Round #29Score 3.5/5Foundation / generic UI

The inputs were accessible, but Form was only styling

Route: /setup
Desktop preview
Mobile preview

Captured 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 label and description APIs on Checkbox from issue #149 and Switch from issue #130 are genuinely good.⁠ They generate IDs and wire up ARIA internally. RadioGroup has proper standard accessibility, and Input automatically shows an error border with aria-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 from Input to Select, Textarea, and PasswordInput.⁠ PasswordInput had a real defect: className applied to its wrapper rather than the input, so aria-invalid produced no red border.⁠ I moved the class to the input and added inputClassName. A browser check measured the aria-invalid border as rgb(252, 176, 176), the error color.
  • Issue #155:⁠ Combobox did not accept aria-invalid or aria-describedby because it failed to pass through HTML attributes. I forwarded them to the trigger, making required comboboxes show an error state.
  • Issue #156:⁠ Textarea had a fixed w-[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 and scheduler rendering layer in : ⁠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

  • ⁠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.

業界別「AI指示書パック」、先行登録を受付中です。