From harness-claude
Builds accessible web forms using labels, fieldsets for grouping, required fields, ARIA for inline validation errors, and top summaries. Use for login, registration, checkout, or multi-step wizards.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Build accessible forms with proper labeling, grouped controls, inline validation, and clear error communication
Guides form UX design with single-column layouts, optimal validation timing (blur/keystroke/submit), smart defaults, error recovery, progressive disclosure, and WCAG accessibility to reduce abandonment.
Generates validated, accessible form pages for contact forms, registrations, surveys, sign-ups, and multi-step wizards. Detects project tech stack to produce matching code with real-time validation, error handling, and a11y.
Implements a11y best practices like semantic HTML, keyboard navigation, ARIA attributes, landmarks, focus management, and WCAG 2.1 AA compliance for UI building and audits.
Share bugs, ideas, or general feedback.
Build accessible forms with proper labeling, grouped controls, inline validation, and clear error communication
<label>. Use htmlFor (React) or for (HTML) to link the label to the input. Clicking the label should focus the input.<label htmlFor="email">Email address</label>
<input id="email" type="email" name="email" />
Never use placeholder text as a substitute for a label — it disappears when the user starts typing and has poor contrast.
<fieldset> and <legend> to group related controls. Screen readers announce the legend as context for each control within the group.<fieldset>
<legend>Shipping Address</legend>
<label for="street">Street</label>
<input id="street" name="street" />
<label for="city">City</label>
<input id="city" name="city" />
</fieldset>
<fieldset>
<legend>Payment method</legend>
<label><input type="radio" name="payment" value="card" /> Credit card</label>
<label><input type="radio" name="payment" value="paypal" /> PayPal</label>
</fieldset>
required attribute for native validation and aria-required="true" for custom validation. Include a visible indicator (asterisk with explanation).<label htmlFor="name">
Full name <span aria-hidden="true">*</span>
</label>
<input id="name" required aria-required="true" />
<p className="form-note">Fields marked with * are required.</p>
aria-invalid to mark the field and aria-describedby or aria-errormessage to point to the error text.<label htmlFor="password">Password</label>
<input
id="password"
type="password"
aria-invalid={!!errors.password}
aria-describedby={errors.password ? 'password-error' : 'password-hint'}
/>
<p id="password-hint">Must be at least 8 characters.</p>
{errors.password && (
<p id="password-error" role="alert" className="error">
{errors.password}
</p>
)}
Use aria-live or role="alert" for dynamic validation messages. When errors appear after form submission or as the user types, screen readers must be notified.
Provide an error summary at the top of the form on submission failure. List all errors with links to the corresponding fields. Move focus to the summary.
{
errors.length > 0 && (
<div role="alert" tabIndex={-1} ref={errorSummaryRef}>
<h2>There are {errors.length} errors in this form</h2>
<ul>
{errors.map((err) => (
<li key={err.field}>
<a href={`#${err.field}`}>{err.message}</a>
</li>
))}
</ul>
</div>
);
}
autocomplete attributes for common fields. This enables browser autofill and password managers, which benefit users with motor and cognitive disabilities.<input name="name" autocomplete="name" />
<input name="email" autocomplete="email" />
<input name="tel" autocomplete="tel" />
<input name="address" autocomplete="street-address" />
<input name="cc-number" autocomplete="cc-number" />
Do not disable the submit button while the form is incomplete. Disabled buttons are not focusable and provide no feedback about what is wrong. Instead, allow submission and show validation errors.
Support keyboard submission. Forms should submit when the user presses Enter in a text input. Use <form> with a <button type="submit"> — do not rely on JavaScript click handlers alone.
Use inputmode and type to show the right keyboard on mobile. type="email" shows an email keyboard, inputmode="numeric" shows a number pad.
Label association methods (in order of preference):
<label for="id"> — explicit association, most reliable<label> wrapping the input — implicit association, works in all browsersaria-label — invisible label, use only when no visible label is possiblearia-labelledby — references another element as the labeltitle attribute — last resort, announced inconsistentlyMulti-step forms: Indicate progress with a step indicator using aria-current="step". Announce step transitions with aria-live. Allow backward navigation without losing data.
Custom select/dropdown: Native <select> is fully accessible. Custom dropdowns must implement the combobox or listbox pattern with full keyboard support and ARIA attributes. Consider whether the customization is worth the complexity.
Common mistakes:
placeholder instead of <label> (disappears, poor contrast)https://www.w3.org/WAI/tutorials/forms/