Use local skill docs only as a convenience after confirming the official API.
Default Stack
Prefer react-hook-form for non-trivial forms.
Use Controller for HeroUI Select and any custom controlled widgets.
Keep one form state. Do not create a second derived validation state unless there is a concrete need the form library cannot express.
Validation Behavior
When RHF controls validation, set HeroUI form fields to validationBehavior="aria".
Do not rely on HeroUI/native validation defaults together with RHF. Native validation can steal focus and submission flow while bypassing the error UI you expect from RHF.
Let RHF own validation rules and submission blocking.
Error Rendering
For HeroUI text fields, use:
isInvalid={Boolean(fieldState.error)}
Conditionally render <FieldError>{fieldState.error.message}</FieldError> inside the same TextField.
Do not invent unsupported props. In particular, do not assume TextField supports an errorMessage prop.
For non-form or custom composite controls, prefer HeroUI ErrorMessage instead of hand-rolled error text.
Use ErrorMessage for collection-style or custom editors that are not true form fields, including key/value editors, tag selectors, and similar composite controls.
Custom Editors
Custom widgets like AgentSelector, EnvEditor, HttpHeaderEditor, and KeyPairEditor should still be registered in RHF through Controller.
For custom editors that manage arrays or compound values, compute validation from the current field value and surface one aggregated error below the editor when possible.
For that aggregated error, prefer HeroUI ErrorMessage.
Do not inject per-row error UI into tight horizontal layouts unless the design explicitly calls for it.
Key/Value Editors
Keep row layout simple:
two inputs
one delete button
no extra wrappers that change flex behavior unless necessary
Prefer aggregate error text below the whole editor over inline row errors. This avoids breaking spacing and alignment.
Implement that aggregate error with HeroUI ErrorMessage, not a custom <p> block.
If you must show row-level issues, redesign the layout first; do not bolt error blocks into a row that was designed as a single-line control.
Practical Rules
Prefer onPress for HeroUI buttons.
Use type="button" for non-submit buttons inside forms.
Preserve existing visual patterns in this repo; do not restyle forms while adding validation.
After form changes, run bun run build in crates/desktop when possible and separate unrelated existing build failures from the changes you made.
Anti-Patterns
Do not mix RHF validation with a parallel validationErrors state for the same fields.
Do not depend on HeroUI default native validation when you expect RHF errors to drive the UI.
Do not push validation messages into each key/value row unless you intentionally redesign that editor.
Do not trust remembered HeroUI APIs for forms without checking the official site first.
1---2name: project-form-patterns3description: aghub Form Patterns4---56# aghub Form Patterns78Follow these rules when building forms in this project.910## Source of Truth1112- Check the official docs first, not memory and not bundled/local docs, when form behavior is in question.13- For HeroUI, prefer the official site:14 - `https://v3.heroui.com/docs/react/components/form`15 - `https://v3.heroui.com/docs/react/components/text-field`16 - `https://v3.heroui.com/docs/react/components/field-error`17 - `https://v3.heroui.com/docs/react/components/select`18- Use local skill docs only as a convenience after confirming the official API.1920## Default Stack2122- Prefer `react-hook-form` for non-trivial forms.23- Use `Controller` for HeroUI `Select` and any custom controlled widgets.24- Keep one form state. Do not create a second derived validation state unless there is a concrete need the form library cannot express.2526## Validation Behavior2728- When RHF controls validation, set HeroUI form fields to `validationBehavior="aria"`.29- Do not rely on HeroUI/native validation defaults together with RHF. Native validation can steal focus and submission flow while bypassing the error UI you expect from RHF.30- Let RHF own validation rules and submission blocking.3132## Error Rendering3334- For HeroUI text fields, use:35 - `isInvalid={Boolean(fieldState.error)}`36 - Conditionally render `<FieldError>{fieldState.error.message}</FieldError>` inside the same `TextField`.37- Do not invent unsupported props. In particular, do not assume `TextField` supports an `errorMessage` prop.38- Keep the official anatomy:3940```tsx41<TextField isInvalid={Boolean(fieldState.error)} validationBehavior="aria">42 <Label>Name</Label>43 <Input {...inputProps} />44 {fieldState.error && <FieldError>{fieldState.error.message}</FieldError>}45</TextField>46```4748- For non-form or custom composite controls, prefer HeroUI `ErrorMessage` instead of hand-rolled error text.49- Use `ErrorMessage` for collection-style or custom editors that are not true form fields, including key/value editors, tag selectors, and similar composite controls.5051## Custom Editors5253- Custom widgets like `AgentSelector`, `EnvEditor`, `HttpHeaderEditor`, and `KeyPairEditor` should still be registered in RHF through `Controller`.54- For custom editors that manage arrays or compound values, compute validation from the current field value and surface one aggregated error below the editor when possible.55- For that aggregated error, prefer HeroUI `ErrorMessage`.56- Do not inject per-row error UI into tight horizontal layouts unless the design explicitly calls for it.5758## Key/Value Editors5960- Keep row layout simple:61 - two inputs62 - one delete button63 - no extra wrappers that change flex behavior unless necessary64- Prefer aggregate error text below the whole editor over inline row errors. This avoids breaking spacing and alignment.65- Implement that aggregate error with HeroUI `ErrorMessage`, not a custom `<p>` block.66- If you must show row-level issues, redesign the layout first; do not bolt error blocks into a row that was designed as a single-line control.6768## Practical Rules6970- Prefer `onPress` for HeroUI buttons.71- Use `type="button"` for non-submit buttons inside forms.72- Preserve existing visual patterns in this repo; do not restyle forms while adding validation.73- After form changes, run `bun run build` in `crates/desktop` when possible and separate unrelated existing build failures from the changes you made.7475## Anti-Patterns7677- Do not mix RHF validation with a parallel `validationErrors` state for the same fields.78- Do not depend on HeroUI default native validation when you expect RHF errors to drive the UI.79- Do not push validation messages into each key/value row unless you intentionally redesign that editor.80- Do not trust remembered HeroUI APIs for forms without checking the official site first.
Run npx skillmds@latest add akarachen/project-form-patterns in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
aghub Form Patterns It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
akarachen (@akarachen) published this skill. Their other Agent Skills are listed on their SkillMD profile.