인터페이스는 현지화되어 있으며, Skill 소개와 설명 문서는 선택한 언어로 AI가 자동 번역합니다. 코드·명령어·경로·전문 용어는 원문을 유지하며 원작자 문서가 우선합니다.
Skills 둘러보기
개발 및 엔지니어링 · SKILL.md

enhance-web-forms

enhance-web-forms

Build or upgrade web forms: accessible structure, schema-driven validation, client↔server parity. Use when "improve this form", "form validation", "accessible form", "multi-step form", "form error handling", or "the form UX is bad".

Independent GitHub snapshot · Automated classification · Original documentation governs

Skill 문서

GitHub

name: enhance-web-forms description: > Build or upgrade web forms: accessible structure, schema-driven validation, client↔server parity. Use when "improve this form", "form validation", "accessible form", "multi-step form", "form error handling", or "the form UX is bad". license: MIT

enhance-web-forms — Production-Quality Forms

Degree of freedom: MIXED. Schema and state-machine judgment [HIGH freedom]; a11y probes and playwright walks [LOW freedom — run exactly].

Forms are where users hand you their data and where apps most often feel broken: unlabeled fields, validation that fires on every keystroke, errors screen readers never announce, a submit button that does nothing visible for three seconds, and no recovery when the request fails. This skill fixes all of that on real forms in the repo.

A form is done when it is accessible, validated on both sides, gives feedback for every state, and recovers from failure. Compile-clean is not done.

Before any browser interaction, read protocol-browser-anti-stall and apply it.

How to reason

  1. Inventory — forms, library, schema; bow out if none
  2. Structure — programmatic labels, types, error association
  3. Parity — one schema both sides; blur + submit, not every keystroke
  4. States — submitting / success / error / unsaved; recover on failure

Worked example

Inventory: signup uses raw <form> + inline if (!email); API validates with zod. Structure: htmlFor labels; autocomplete="email"; aria-invalid + summary. Parity: share the zod schema; validate on blur/submit; map "email taken" to the field. States: submit disables + aria-busy; values preserved on 500; dirty-nav warn.

Self-critique before reporting

  • Labeled — placeholder is never the only name
  • Both sides — client and server rules match; error shapes map to fields
  • Walked — empty, invalid, valid, and server-error paths in the browser
  • Right owner — page/flow UX beyond the form → enhance-web-ux; WCAG sweep → audit-accessibility

Phase 0 — Detect the stack and inventory forms [HIGH freedom]

cat package.json | grep -iE "react-hook-form|formik|@tanstack/react-form|final-form|zod|yup|valibot|superstruct"
rg -n "<form|onSubmit|useForm|handleSubmit" -g "*.{tsx,jsx,vue,svelte}" -l

Record: form library (or native), validation/schema library, UI/component library, and the list of forms to enhance (auth, checkout, settings, contact, search, etc.). If there are no forms, bow out.


Phase 1 — Research + prioritize [HIGH freedom]

Follow /research: Context7 for the detected form/validation library's current API; Firecrawl for current form UX/a11y guidance dated to now. Prioritize forms by traffic and risk (auth, payment, destructive actions first).


Phase 2 — Accessible structure (the foundation) [HIGH freedom]

For each form, verify/fix:

  • Every input has a programmatic label — <label htmlFor> or aria-label; placeholder is not a label.
  • Correct input types + autocomplete — type="email|tel|url|number", inputmode, autocomplete="email|current-password|cc-number|..." for autofill.
  • Grouping — related inputs in <fieldset> + <legend> (radio groups, address blocks).
  • Required + optional — marked in text, not color alone; required / aria-required.
  • Keyboard + focus — logical tab order, visible focus ring, Enter submits, no keyboard traps.
  • Error association — each field error linked via aria-describedby; invalid fields get aria-invalid="true"; a form-level error summary with links to fields on submit failure.
rg -n "placeholder=" -g "*.{tsx,jsx}"        # placeholders masquerading as labels?
rg -n "aria-describedby|aria-invalid|htmlFor|aria-label" -g "*.{tsx,jsx}" -c

Phase 3 — Validation (schema-driven, both sides) [HIGH freedom]

  • Single schema as SSOT — define validation once (zod/yup/valibot) and share it between client and server so rules can't drift. If the backend validates separately, reconcile the two so error shapes match.
  • Timing — validate on blur and on submit, not on every keystroke; re-validate a field on change after it has errored once (so users see fixes immediately).
  • Messages — specific and actionable ("Password needs 8+ characters", not "Invalid").
  • Server errors — map field-level server errors back onto the right inputs; show form-level errors (e.g. "Email already registered") in the summary.

Phase 4 — States & feedback (every one, no gaps) [HIGH freedom]

Wire the full state machine for each form and submit:

StateRequired behavior
IdleClean, submit enabled/disabled per validity policy
ValidatingInline field feedback (see Phase 3 timing)
SubmittingSubmit shows spinner/label swap + disabled + aria-busy; prevent double-submit
SuccessConfirmation (toast/inline/redirect); reset or lock as appropriate
ErrorPreserve entered values; surface the failure; keep the user's place; retry path
Empty/optionalSensible defaults; empty state for dependent selects

Also handle:

  • Multi-step — progress indicator, per-step validation, back/forward preserves data, final review before submit.
  • Unsaved-changes guard — warn on navigation away from a dirty form.
  • Autosave / draft — for long forms, if the app already has a persistence pattern.
  • Micro-feedback — subtle transitions on error/success via design-motion conventions (reduced-motion safe). Don't animate layout in a way that shifts fields.

Phase 5 — Verify and report [LOW freedom — do not skip]

  • playwright-cli: walk each form — tab through it, submit empty (see the error summary + focus moves to first error), submit invalid, submit valid, force a server error. Check console. Confirm screen-reader names via the accessibility snapshot. Screenshots to .playwright-mcp/.
  • Build/typecheck/lint: run the repo's commands.
## Forms Enhancement — report
**Stack:** form=[..] · validation=[..] · UI=[..]
**Forms upgraded:** [list]
**Structure:** labels/types/autocomplete/fieldsets fixed on [N] forms
**Validation:** shared schema SSOT · client↔server parity · blur+submit timing
**States:** submitting/success/error/multi-step/unsaved-guard wired
**A11y:** error summary + aria-describedby/aria-invalid + focus management (evidence)
**Verification:** build ✓ · console clean ✓ · flows walked (screenshots [paths])

Related

  • audit-accessibility — deep WCAG audit (run to verify the a11y work)
  • audit-ux — form usability heuristics, microcopy, cognitive load
  • audit-fe-api — validate the submit request/response contract against the backend
  • backend-error-handling — server-side validation + structured error responses
  • design-motion — reduced-motion-safe micro-feedback for error/success
  • enhance-web-ux — broader page/flow UX beyond the form itself
저장한 Skills