{"id":"fa227312-bb1f-445c-a8a0-0aeaa5f341a7","shortId":"JXSssZ","kind":"skill","title":"Form UX Optimizer","tagline":"Reviews web forms for usability issues — field ordering, validation messages, error states, and accessibility.","description":"# Form UX Optimizer\n\n## What this skill does\n\nThis skill reviews the code and design of web forms to identify usability and accessibility issues. It checks for poor field ordering, confusing labels, missing or unhelpful error messages, incorrect input types, broken keyboard navigation, and accessibility violations. The output is a prioritized list of specific improvements with code examples for each fix.\n\nUse this before shipping a registration, checkout, contact, or any data-entry form — especially when your form has a high abandonment rate or you're getting support requests about users not knowing what to enter.\n\n## How to use\n\n### Claude Code / Cline\n\nCopy this file to `.agents/skills/form-ux-optimizer/SKILL.md` in your project root.\n\nThen ask:\n- *\"Use the Form UX Optimizer skill to review our checkout form in `CheckoutForm.tsx`.\"*\n- *\"Review this registration form for UX and accessibility issues using the Form UX Optimizer skill.\"*\n\nProvide the form component code and, if available, any validation logic.\n\n### Cursor\n\nAdd the instructions below to your `.cursorrules` or paste them into the Cursor AI pane. Provide the form code to review.\n\n### Codex\n\nPaste the form HTML/JSX and validation code. Ask Codex to follow the instructions below.\n\n## The Prompt / Instructions for the Agent\n\nWhen asked to review a form for UX, follow this checklist systematically:\n\n### Category 1 — Field design and labeling\n\n**Labels**\n- Every input must have a visible `<label>` element (not just placeholder text)\n- Labels must be associated with inputs via `for`/`htmlFor` or wrapping\n- Placeholder text must not be used as a substitute for labels — it disappears on input and has poor contrast\n- Required fields must be clearly marked (e.g., asterisk with a legend explaining it means required)\n\n**Field order**\n- Fields should follow a logical, natural sequence (name before email, shipping before billing)\n- Related fields should be grouped visually and in DOM order\n- The most important or most-filled field should come first, not last\n\n**Input types**\n- Phone number fields must use `type=\"tel\"` (shows numeric keyboard on mobile)\n- Email fields must use `type=\"email\"` (enables autocomplete and basic validation)\n- Number inputs must use `type=\"number\"` where appropriate\n- Date inputs must use `type=\"date\"` or a proper date picker, not three separate text inputs\n- Password fields must use `type=\"password\"`\n- Search fields must use `type=\"search\"`\n\n**Autocomplete**\n- Common fields should have `autocomplete` attributes set: `autocomplete=\"email\"`, `autocomplete=\"given-name\"`, `autocomplete=\"tel\"`, `autocomplete=\"current-password\"`, `autocomplete=\"new-password\"`, etc.\n- This enables browser autofill and password manager integration\n\n### Category 2 — Validation and errors\n\n**Error messages**\n- Error messages must be specific: \"Email is required\" is better than \"Invalid input\"; \"Password must be at least 8 characters\" is better than \"Invalid password\"\n- Errors should tell the user what to do, not just what went wrong: \"Enter a valid email address\" not \"Email invalid\"\n- Errors must appear near the field they relate to, not only at the top of the form\n- Error messages must be associated with their input via `aria-describedby` or `aria-errormessage`\n\n**Validation timing**\n- Don't validate on every keystroke — it's annoying while the user is still typing\n- Validate on `blur` (when the user leaves a field) for format errors\n- Validate on submit for completeness\n\n**Inline validation**\n- Show a success indicator when a field is correctly filled (a checkmark) — reduces anxiety, especially for passwords and usernames\n- For password strength, use a visual strength meter, not just a minimum length error\n\n**Error state styling**\n- Error states must not rely on color alone (red border alone fails WCAG for color-blind users — add an icon or text)\n- Error state must be clearly visually distinct from the default state\n\n### Category 3 — Accessibility\n\n- Every form must have a `<form>` element (not just `<div>`)\n- Submit button must be a `<button type=\"submit\">` or `<input type=\"submit\">` — not a `<div>` with an `onClick`\n- The form must be fully operable with a keyboard alone (Tab to advance, Shift+Tab to go back, Enter to submit)\n- Focus indicators must be visible — never `outline: none` without a replacement\n- `aria-required=\"true\"` should be present on required fields in addition to HTML `required`\n- `aria-invalid=\"true\"` should be set on fields with validation errors\n- `aria-live=\"polite\"` region should announce error messages to screen readers when they appear\n\n### Category 4 — Form-level UX\n\n- The submit button label should describe the action: \"Create Account\", \"Place Order\", \"Send Message\" — not just \"Submit\"\n- Show a loading state on the submit button while the form is being processed\n- After a successful submission, give clear feedback — don't just clear the form silently\n- For multi-step forms, show a progress indicator\n- For long forms, consider grouping with `<fieldset>` and `<legend>`\n\n### Output format\n\n```markdown\n## Form UX Review — [Form Name]\n\n### Critical Issues (accessibility violations or blocking UX problems)\n\n#### 1. [Issue title]\n- **Field / Location**: [Field name or line number]\n- **Problem**: [What's wrong and why it matters]\n- **Fix**: [Specific code change with example]\n\n### High-Priority Issues (significant UX degradation)\n\n[Same format]\n\n### Warnings (minor issues or best practice gaps)\n\n[Same format]\n\n### What's Already Good\n[Brief acknowledgment of things done well]\n```\n\n## Example\n\n**Input to Agent:**\n> \"Use the Form UX Optimizer skill on this form:\n> ```jsx\n> <div>\n>   <input placeholder=\"Email\" onChange={...} />\n>   <input placeholder=\"Password\" type=\"password\" onChange={...} />\n>   <div onClick={handleSubmit} className=\"btn\">Go</div>\n> </div>\n> ```\"\n\n**Output from Agent:**\n\n> ## Form UX Review — Login Form\n>\n> ### Critical Issues\n>\n> #### 1. No `<label>` elements — placeholders used as labels\n> - **Problem**: When the user starts typing, the placeholder disappears and they lose the field context. Screen readers also cannot reliably read placeholders as labels.\n> - **Fix**:\n>   ```jsx\n>   <label htmlFor=\"email\">Email</label>\n>   <input id=\"email\" type=\"email\" placeholder=\"you@example.com\" autocomplete=\"email\" />\n>   ```\n>\n> #### 2. Submit is a `<div>`, not a `<button>`\n> - **Problem**: A `<div>` is not keyboard-accessible by default, is not announced as a button by screen readers, and doesn't submit the form on Enter.\n> - **Fix**: `<button type=\"submit\">Sign in</button>` — rename \"Go\" to something descriptive.\n>\n> #### 3. No `<form>` wrapper\n> - **Problem**: Without a `<form>` element, the browser's built-in form submission, validation, and Enter-to-submit behavior is lost.\n> - **Fix**: Wrap in `<form onSubmit={handleSubmit}>` and remove the `onClick` from the button.\n>\n> ### High-Priority Issues\n>\n> #### 4. Email input missing `type=\"email\"`\n> - **Problem**: Without `type=\"email\"`, mobile devices show a standard keyboard instead of the optimized email keyboard. Browser-level email validation is also disabled.\n> - **Fix**: `<input type=\"email\" ... />`\n\n## Notes\n\n- This skill reviews code; it doesn't test the form in a browser. Some issues (focus order, screen reader behavior) require manual testing or automated tools like axe-core.\n- For checkout forms, the two highest-impact fixes are usually: (1) adding autocomplete attributes and (2) improving error messages. These alone can noticeably improve completion rates.\n- Run the axe browser extension on your form after implementing fixes to catch any remaining accessibility issues.","tags":["form","optimizer","openagentskills","notysoty","agent-skills","claude","claude-code","claude-skills","cline","cursor","llm","llm-skills"],"capabilities":["skill","source-notysoty","skill-form-ux-optimizer","topic-agent-skills","topic-claude","topic-claude-code","topic-claude-skills","topic-cline","topic-cursor","topic-llm","topic-llm-skills","topic-skills"],"categories":["openagentskills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/Notysoty/openagentskills/form-ux-optimizer","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add Notysoty/openagentskills","source_repo":"https://github.com/Notysoty/openagentskills","install_from":"skills.sh"}},"qualityScore":"0.454","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (7,655 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:13:21.829Z","embedding":null,"createdAt":"2026-05-18T13:20:42.754Z","updatedAt":"2026-05-18T19:13:21.829Z","lastSeenAt":"2026-05-18T19:13:21.829Z","tsv":"'1':226,791,883,1071 '2':421,917,1076 '3':613,957 '4':709,998 '8':445 'abandon':99 'access':17,39,61,151,614,785,929,1102 'account':723 'acknowledg':838 'action':721 'ad':1072 'add':171,596 'addit':677 'address':469 'advanc':646 'agent':212,846,875 'agents/skills/form-ux-optimizer/skill.md':124 'ai':184 'alon':585,588,643,1081 'alreadi':835 'also':907,1026 'announc':699,934 'annoy':516 'anxieti':555 'appear':475,707 'appropri':358 'aria':500,504,667,682,694 'aria-describedbi':499 'aria-errormessag':503 'aria-invalid':681 'aria-l':693 'aria-requir':666 'ask':130,200,214 'associ':246,494 'asterisk':280 'attribut':393,1074 'autocomplet':347,387,392,395,397,401,403,407,1073 'autofil':415 'autom':1054 'avail':166 'axe':1058,1089 'axe-cor':1057 'back':651 'basic':349 'behavior':978,1049 'best':828 'better':436,448 'bill':302 'blind':594 'block':788 'blur':525 'border':587 'brief':837 'broken':57 'browser':414,965,1021,1042,1090 'browser-level':1020 'btn':871 'built':968 'built-in':967 'button':624,716,738,937,993 'cannot':908 'catch':1099 'categori':225,420,612,708 'chang':812 'charact':446 'check':42 'checklist':223 'checkmark':553 'checkout':84,140,1061 'checkoutform.tsx':143 'classnam':870 'claud':117 'clear':277,605,750,755 'cline':119 'code':29,73,118,163,189,199,811,1033 'codex':192,201 'color':584,593 'color-blind':592 'come':322 'common':388 'complet':539,1085 'compon':162 'confus':47 'consid':771 'contact':85 'context':904 'contrast':272 'copi':120 'core':1059 'correct':550 'creat':722 'critic':783,881 'current':405 'current-password':404 'cursor':170,183 'cursorrul':177 'data':89 'data-entri':88 'date':359,364,368 'default':610,931 'degrad':821 'describ':719 'describedbi':501 'descript':956 'design':31,228 'devic':1009 'disabl':1027 'disappear':266,898 'distinct':607 'div':867 'doesn':942,1035 'dom':311 'done':841 'e.g':279 'element':238,620,885,963 'email':299,340,345,396,432,468,471,859,916,999,1003,1007,1018,1023 'enabl':346,413 'enter':113,465,652,948,975 'enter-to-submit':974 'entri':90 'error':14,52,424,425,427,452,473,490,534,574,575,578,601,692,700,1078 'errormessag':505 'especi':92,556 'etc':411 'everi':232,512,615 'exampl':74,814,843 'explain':284 'extens':1091 'fail':589 'feedback':751 'field':10,45,227,274,288,290,304,320,330,341,376,382,389,478,531,548,675,689,794,796,903 'file':122 'fill':319,551 'first':323 'fix':77,809,914,949,981,1028,1068,1097 'focus':655,1045 'follow':203,221,292 'form':1,6,18,34,91,95,133,141,147,155,161,188,195,218,489,616,635,711,741,757,763,770,778,781,849,855,876,880,946,970,984,1039,1062,1094 'form-level':710 'format':533,776,823,832 'fulli':638 'gap':830 'get':104 'give':749 'given':399 'given-nam':398 'go':650,872,953 'good':836 'group':307,772 'handlesubmit':869,986 'high':98,816,995 'high-prior':815,994 'highest':1066 'highest-impact':1065 'html':679 'html/jsx':196 'htmlfor':251 'icon':598 'identifi':36 'impact':1067 'implement':1096 'import':315 'improv':71,1077,1084 'incorrect':54 'indic':545,656,767 'inlin':540 'input':55,233,248,268,326,352,360,374,439,497,844,857,861,1000 'instead':1014 'instruct':173,205,209 'integr':419 'invalid':438,450,472,683 'issu':9,40,152,784,792,818,826,882,997,1044,1103 'jsx':856,915 'keyboard':58,337,642,928,1013,1019 'keyboard-access':927 'keystrok':513 'know':110 'label':48,230,231,243,264,717,889,913 'last':325 'least':444 'leav':529 'legend':283 'length':573 'level':712,1022 'like':1056 'line':799 'list':68 'live':695 'load':733 'locat':795 'logic':169,294 'login':879 'long':769 'lose':901 'lost':980 'manag':418 'manual':1051 'mark':278 'markdown':777 'matter':808 'mean':286 'messag':13,53,426,428,491,701,727,1079 'meter':568 'minimum':572 'minor':825 'miss':49,1001 'mobil':339,1008 'most-fil':317 'multi':761 'multi-step':760 'must':234,244,256,275,331,342,353,361,377,383,429,441,474,492,580,603,617,625,636,657 'name':297,400,782,797 'natur':295 'navig':59 'near':476 'never':660 'new':409 'new-password':408 'none':662 'note':1029 'notic':1083 'number':329,351,356,800 'numer':336 'onchang':860,866 'onclick':633,868,990 'onsubmit':985 'oper':639 'optim':3,20,135,157,851,1017 'order':11,46,289,312,725,1046 'outlin':661 'output':64,775,873 'pane':185 'password':375,380,406,410,417,440,451,558,562,863,865 'past':179,193 'phone':328 'picker':369 'place':724 'placehold':241,254,858,862,886,897,911 'polit':696 'poor':44,271 'practic':829 'present':672 'priorit':67 'prioriti':817,996 'problem':790,801,890,923,960,1004 'process':744 'progress':766 'project':127 'prompt':208 'proper':367 'provid':159,186 'rate':100,1086 're':103 'read':910 'reader':704,906,940,1048 'red':586 'reduc':554 'region':697 'registr':83,146 'relat':303,480 'reli':582 'reliabl':909 'remain':1101 'remov':988 'renam':952 'replac':665 'request':106 'requir':273,287,434,668,674,680,1050 'review':4,27,138,144,191,216,780,878,1032 'root':128 'run':1087 'screen':703,905,939,1047 'search':381,386 'send':726 'separ':372 'sequenc':296 'set':394,687 'shift':647 'ship':81,300 'show':335,542,731,764,1010 'sign':950 'signific':819 'silent':758 'skill':23,26,136,158,852,1031 'skill-form-ux-optimizer' 'someth':955 'source-notysoty' 'specif':70,431,810 'standard':1012 'start':894 'state':15,576,579,602,611,734 'step':762 'still':521 'strength':563,567 'style':577 'submiss':748,971 'submit':537,623,654,715,730,737,918,944,977 'substitut':262 'success':544,747 'support':105 'systemat':224 'tab':644,648 'tel':334,402 'tell':454 'test':1037,1052 'text':242,255,373,600 'thing':840 'three':371 'time':507 'titl':793 'tool':1055 'top':486 'topic-agent-skills' 'topic-claude' 'topic-claude-code' 'topic-claude-skills' 'topic-cline' 'topic-cursor' 'topic-llm' 'topic-llm-skills' 'topic-skills' 'true':669,684 'two':1064 'type':56,327,333,344,355,363,379,385,522,864,895,1002,1006 'unhelp':51 'usabl':8,37 'use':78,116,131,153,259,332,343,354,362,378,384,564,847,887 'user':108,456,519,528,595,893 'usernam':560 'usual':1070 'ux':2,19,134,149,156,220,713,779,789,820,850,877 'valid':12,168,198,350,422,467,506,510,523,535,541,691,972,1024 'via':249,498 'violat':62,786 'visibl':237,659 'visual':308,566,606 'warn':824 'wcag':590 'web':5,33 'well':842 'went':463 'without':663,961,1005 'wrap':253,982 'wrapper':959 'wrong':464,804","prices":[{"id":"ded35d09-246e-4c4a-bb9a-e43d635630be","listingId":"fa227312-bb1f-445c-a8a0-0aeaa5f341a7","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"Notysoty","category":"openagentskills","install_from":"skills.sh"},"createdAt":"2026-05-18T13:20:42.754Z"}],"sources":[{"listingId":"fa227312-bb1f-445c-a8a0-0aeaa5f341a7","source":"github","sourceId":"Notysoty/openagentskills/form-ux-optimizer","sourceUrl":"https://github.com/Notysoty/openagentskills/tree/main/skills/form-ux-optimizer","isPrimary":false,"firstSeenAt":"2026-05-18T13:20:42.754Z","lastSeenAt":"2026-05-18T19:13:21.829Z"}],"details":{"listingId":"fa227312-bb1f-445c-a8a0-0aeaa5f341a7","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"Notysoty","slug":"form-ux-optimizer","github":{"repo":"Notysoty/openagentskills","stars":8,"topics":["agent-skills","claude","claude-code","claude-skills","cline","cursor","llm","llm-skills","skills"],"license":"mit","html_url":"https://github.com/Notysoty/openagentskills","pushed_at":"2026-03-28T06:50:19Z","description":"A  community-driven library of reusable AI agent skills for Claude Code, Cursor, Codex, Cline, and more.","skill_md_sha":"863b703ed3e486644d0ec6b067f5cad47e8626b6","skill_md_path":"skills/form-ux-optimizer/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/Notysoty/openagentskills/tree/main/skills/form-ux-optimizer"},"layout":"multi","source":"github","category":"openagentskills","frontmatter":{"name":"Form UX Optimizer","description":"Reviews web forms for usability issues — field ordering, validation messages, error states, and accessibility."},"skills_sh_url":"https://skills.sh/Notysoty/openagentskills/form-ux-optimizer"},"updatedAt":"2026-05-18T19:13:21.829Z"}}