Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-html --skill forms
The command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
<formid="contact-form"action="/api/contact"method="POST"novalidatearia-labelledby="form-title"><h2id="form-title">Contact Us</h2><!-- Error Summary (initially hidden) --><divid="error-summary"role="alert"aria-live="polite"hidden><h3>Please fix the following errors:</h3><ulid="error-list"></ul></div><!-- Name Field --><divclass="field"><labelfor="name">
Full Name
<spanclass="required"aria-hidden="true">*</span></label><inputtype="text"id="name"name="name"requiredaria-required="true"autocomplete="name"aria-describedby="name-hint"><pid="name-hint"class="hint">Enter your full name</p><pid="name-error"class="error"aria-live="polite"></p></div><!-- Email Field --><divclass="field"><labelfor="email">
Email
<spanclass="required"aria-hidden="true">*</span></label><inputtype="email"id="email"name="email"requiredaria-required="true"autocomplete="email"aria-describedby="email-hint email-error"><pid="email-hint"class="hint">We'll never share your email</p><pid="email-error"class="error"aria-live="polite"></p></div><!-- Message Field --><divclass="field"><labelfor="message">
Message
<spanclass="required"aria-hidden="true">*</span></label><textareaid="message"name="message"rows="5"requiredaria-required="true"minlength="10"maxlength="1000"aria-describedby="message-hint message-count"></textarea><pid="message-hint"class="hint">10-1000 characters</p><pid="message-count"class="hint"aria-live="polite">0/1000</p><pid="message-error"class="error"aria-live="polite"></p></div><buttontype="submit">Send Message</button></form>
3. Constraint Validation API
const form = document.getElementById('contact-form');
const inputs = form.querySelectorAll('input, textarea, select');
// Disable browser default validation UI
form.setAttribute('novalidate', '');
// Validate on submit
form.addEventListener('submit', (e) => {
if (!validateForm()) {
e.preventDefault();
showErrorSummary();
focusFirstError();
}
});
// Validate on blur for immediate feedback
inputs.forEach(input => {
input.addEventListener('blur', () =>validateField(input));
input.addEventListener('input', () => {
if (input.classList.contains('invalid')) {
validateField(input);
}
});
});
functionvalidateForm() {
let isValid = true;
inputs.forEach(input => {
if (!validateField(input)) {
isValid = false;
}
});
return isValid;
}
functionvalidateField(input) {
const errorEl = document.getElementById(`${input.id}-error`);
// Check validity using Constraint Validation APIif (!input.checkValidity()) {
const message = getErrorMessage(input);
showError(input, errorEl, message);
returnfalse;
}
clearError(input, errorEl);
returntrue;
}
functiongetErrorMessage(input) {
const validity = input.validity;
if (validity.valueMissing) {
return`${input.labels[0].textContent} is required`;
}
if (validity.typeMismatch) {
return`Please enter a valid ${input.type}`;
}
if (validity.patternMismatch) {
return input.dataset.patternError || 'Please match the requested format';
}
if (validity.tooShort) {
return`Must be at least ${input.minLength} characters`;
}
if (validity.tooLong) {
return`Must be no more than ${input.maxLength} characters`;
}
if (validity.rangeUnderflow) {
return`Must be at least ${input.min}`;
}
if (validity.rangeOverflow) {
return`Must be no more than ${input.max}`;
}
return input.validationMessage;
}
functionshowError(input, errorEl, message) {
input.classList.add('invalid');
input.setAttribute('aria-invalid', 'true');
input.setAttribute('aria-errormessage', errorEl.id);
errorEl.textContent = message;
errorEl.hidden = false;
}
functionclearError(input, errorEl) {
input.classList.remove('invalid');
input.removeAttribute('aria-invalid');
input.removeAttribute('aria-errormessage');
errorEl.textContent = '';
errorEl.hidden = true;
}
functionfocusFirstError() {
const firstError = form.querySelector('.invalid');
if (firstError) {
firstError.focus();
}
}
Debug Checklist:
□ Error container has role="alert"?
□ aria-live="polite" or "assertive" set?
□ Error linked via aria-errormessage?
□ aria-invalid="true" on field?
□ Error content actually changing?
Problem: Autocomplete not working
Debug Checklist:
□ autocomplete attribute present?
□ Correct autocomplete value?
□ Input has name attribute?
□ Form has action?
□ Browser autocomplete enabled?
Autocomplete Values
Value
Purpose
name
Full name
given-name
First name
family-name
Last name
email
Email address
tel
Phone number
street-address
Street address
postal-code
ZIP/Postal code
country
Country
cc-number
Credit card number
cc-exp
Card expiration
cc-csc
Security code
username
Username
current-password
Current password
new-password
New password
📊 Form Types
Login Form
<formaction="/login"method="POST"aria-labelledby="login-title"><h2id="login-title">Sign In</h2><divclass="field"><labelfor="username">Email or Username</label><inputtype="text"id="username"name="username"requiredautocomplete="username"autofocus></div><divclass="field"><labelfor="password">Password</label><inputtype="password"id="password"name="password"requiredautocomplete="current-password"minlength="8"><ahref="/forgot-password">Forgot password?</a></div><labelclass="checkbox"><inputtype="checkbox"name="remember"value="1">
Remember me
</label><buttontype="submit">Sign In</button><p>Don't have an account? <ahref="/register">Sign up</a></p></form>
Search Form
<formrole="search"action="/search"method="GET"aria-label="Site search"><labelfor="search-input"class="visually-hidden">
Search
</label><inputtype="search"id="search-input"name="q"placeholder="Search..."autocomplete="off"aria-describedby="search-hint"><buttontype="submit"aria-label="Submit search"><svgaria-hidden="true">...</svg></button><pid="search-hint"class="visually-hidden">
Enter keywords to search
</p></form>
# Create contact formskill:formsoperation:createform_type:contactoptions:validation_mode:hybridaccessibility_level:"AA"autocomplete:true# Validate form markupskill:formsoperation:validatemarkup:"<form>...</form>"# Get login form patternskill:formsoperation:patternform_type:login