A bank form exposed an ARIA bug that every generic demo had hidden
/transferCaptured 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
A bank form exposed an ARIA bug that every generic demo had hidden
Build log series: I hand a real screen to an AI that has never seen Gunjo (
@gunjo/ui) and let it build. This round, at a reader's suggestion, took on an industry-specific screen: a Japanese online-banking transfer flow (source account, recipient, amount, confirmation, identity check, result).
Same setup as always: only the shipped npm package and the docs site, no source access. Digit-grouped amounts, masked account numbers, balance checks, identity verification: finance-specific constraints never come up on generic screens.
Result: 4/5
tsc and build passed, the console stayed clear, I verified 375px and desktop, and every field's error state was wired up through ARIA.
The star this round: a strict banking form flushed out a hidden accessibility bug
The form system built across #29 and #30 (FormField and FormControl wiring ids and aria automatically) was certified as "real" by #30's agent. Two rounds later, the bank form produced an actual bug:
🔴
FormControlinjectsaria-describedby="...-description"even on fields that have noFormDescription, pointing at an id that does not exist. That is an ARIA bug axe (the accessibility checker) rejects.
A transfer form is full of fields with no description text (bank name, branch name, account type). A generic demo that dutifully gives every field a description can never trigger this defect. It took a banking screen, an industry pattern made of description-less fields, to expose it.
The fix (issue #175, landed in the same PR)
FormField now checks whether a FormDescription child actually exists and reserves the description id only when it does. Without one, the shared state is undefined and FormControl drops the attribute. The decision happens at render time, so it is safe under server rendering and hydration. Verified in a browser: the three description-less controls in the docs now show aria-describedby: null, zero dangling references.
Industry-specific screens surface a different layer of gaps
The reader's instinct was right. Gaps that never appeared on generic screens (settings, ecommerce, dashboards) poured out of a banking form:
- 🟠 No amount-input component.
NumberInputis an<input type=number>, so it cannot express1,000,000with digit grouping. No yen prefix, no locale handling. It is front and center on every ecommerce, billing, and banking screen, and it got hand-rolled (issue #176, the biggest gap, headed to Codex). - 🟠 No masked-display component for account numbers (
ordinary ****1234, the account type plus a masked number; issue #177), and noDescriptionListfor the confirmation summary (issue #178). - 🟠 The Stepper still is not interactive (issue #157 reconfirmed), and there is no validation state layer (issue #166 reconfirmed).
The foundation still held: the compounding continues
What the agent singled out for praise was, once again, the fixes from earlier rounds:
- Form and FormField were the standout: "zero hand-written ARIA on the wired fields. Four invalid states each connect to their
role=alertthrough describedby." - Select label (issue #164), RadioGroupItem label (issue #162), CardTitle and AlertTitle
as(issues #116 and #163), StatusScreen headingLevel (issue #104), and PasswordInput (which keeps the PIN out of the accessibility tree) all drew praise. - Dark mode inverted automatically (
bg-cardfrom white torgb(2,8,23)).
What I took away
Generic demos: every field carries a description, so the bug stays hidden
Industry screen (banking): description-less fields everywhere, so the hidden bug surfaces
Change the industry and a different face of the code gets tested. My overview post claims the system "covers the hard twenty percent". Rather than asserting that, I get to prove it one piece at a time, like this.
Next up: build log #33
- Another industry: an insurance or medical form, logistics tracking, or a POS. The more the industry changes, the more gaps fall out.
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.