codingwithagent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/bin/init.js +257 -0
- package/package.json +56 -0
- package/templates/accessibility/.cursorrules +342 -0
- package/templates/accessibility/README.md +47 -0
- package/templates/antigravity/accessibility/.agent/rules/accessibility.md +501 -0
- package/templates/antigravity/accessibility/.agent/rules/aria-patterns.md +568 -0
- package/templates/antigravity/accessibility/.agent/rules/wcag-standard.md +225 -0
- package/templates/antigravity/accessibility/README.md +42 -0
- package/templates/antigravity/minimal/.agent/rules/accessibility.md +53 -0
- package/templates/antigravity/minimal/.agent/rules/code-quality.md +86 -0
- package/templates/antigravity/minimal/.agent/rules/react-components.md +164 -0
- package/templates/antigravity/minimal/README.md +34 -0
- package/templates/antigravity/standard/.agent/rules/accessibility.md +98 -0
- package/templates/antigravity/standard/.agent/rules/code-quality.md +166 -0
- package/templates/antigravity/standard/.agent/rules/pull-request-review.md +192 -0
- package/templates/antigravity/standard/.agent/rules/react-components.md +204 -0
- package/templates/antigravity/standard/.agent/rules/testing.md +197 -0
- package/templates/antigravity/standard/README.md +39 -0
- package/templates/antigravity/strict/.agent/README.md +46 -0
- package/templates/antigravity/strict/.agent/rules/accessibility.md +199 -0
- package/templates/antigravity/strict/.agent/rules/code-quality.md +268 -0
- package/templates/antigravity/strict/.agent/rules/pull-request-review.md +114 -0
- package/templates/antigravity/strict/.agent/rules/react-components.md +423 -0
- package/templates/antigravity/strict/.agent/rules/security.md +483 -0
- package/templates/antigravity/strict/.agent/rules/testing.md +280 -0
- package/templates/minimal/.cursorrules +48 -0
- package/templates/minimal/README.md +40 -0
- package/templates/standard/.cursorrules +184 -0
- package/templates/standard/README.md +43 -0
- package/templates/strict/.cursorrules +227 -0
- package/templates/strict/README.md +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nitish Kafle
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# ๐ค Agentic Code Standards
|
|
2
|
+
|
|
3
|
+
**Production-ready coding standards and best practices for AI coding agents**
|
|
4
|
+
|
|
5
|
+
Stop fighting with inconsistent AI code output. Get enterprise-grade standards that work across **all major AI coding tools** โ Cursor, Windsurf, Google Antigravity, GitHub Copilot, Cline, and more.
|
|
6
|
+
|
|
7
|
+
## ๐ฏ What You Get
|
|
8
|
+
|
|
9
|
+
- โฟ **Accessibility-First**: WCAG 2.1 AA+ compliance built-in
|
|
10
|
+
- โ๏ธ **Modern Stack**: React, TypeScript, Node.js, Python best practices
|
|
11
|
+
- ๐งช **Testing Ready**: Unit, integration, E2E testing standards
|
|
12
|
+
- ๐ **Security**: OpenSSF-aligned secure coding practices
|
|
13
|
+
- ๐ **Code Quality**: Maintainable, scalable patterns from day one
|
|
14
|
+
- ๐ **Universal**: One standard, every AI coding agent
|
|
15
|
+
|
|
16
|
+
## ๐ Quick Start
|
|
17
|
+
|
|
18
|
+
# Using npx (no installation needed!)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx codingwithagent init
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
# Or install globally
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
npm i -g codingwithagent
|
|
28
|
+
codingwithagent init
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Choose your setup:
|
|
32
|
+
|
|
33
|
+
- Minimal (essential rules only)
|
|
34
|
+
- Standard (recommended baseline) โญ
|
|
35
|
+
- Strict (all rules enforced)
|
|
36
|
+
- Accessibility-focused
|
|
37
|
+
- Custom (pick and choose)
|
package/bin/init.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Agentic Code Standards CLI
|
|
5
|
+
* Interactive installer for AI coding agent standards
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
|
|
12
|
+
const rl = readline.createInterface({
|
|
13
|
+
input: process.stdin,
|
|
14
|
+
output: process.stdout
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// ANSI colors
|
|
18
|
+
const colors = {
|
|
19
|
+
reset: '\x1b[0m',
|
|
20
|
+
bright: '\x1b[1m',
|
|
21
|
+
cyan: '\x1b[36m',
|
|
22
|
+
green: '\x1b[32m',
|
|
23
|
+
yellow: '\x1b[33m',
|
|
24
|
+
blue: '\x1b[34m',
|
|
25
|
+
red: '\x1b[31m'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function log(message, color = 'reset') {
|
|
29
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function header() {
|
|
33
|
+
console.log('');
|
|
34
|
+
log('๐ค Agentic Code Standards', 'cyan');
|
|
35
|
+
log('โ'.repeat(60), 'cyan');
|
|
36
|
+
log('Production-ready standards for AI coding agents', 'bright');
|
|
37
|
+
console.log('');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function detectAITool() {
|
|
41
|
+
const cwd = process.cwd();
|
|
42
|
+
|
|
43
|
+
if (fs.existsSync(path.join(cwd, '.cursorrules'))) return 'cursor';
|
|
44
|
+
if (fs.existsSync(path.join(cwd, '.windsurfrules'))) return 'windsurf';
|
|
45
|
+
if (fs.existsSync(path.join(cwd, '.agent'))) return 'antigravity';
|
|
46
|
+
if (fs.existsSync(path.join(cwd, '.github', 'copilot-instructions.md'))) return 'copilot';
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function question(prompt) {
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
rl.question(`${colors.bright}${prompt}${colors.reset} `, resolve);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function selectProfile() {
|
|
58
|
+
console.log('');
|
|
59
|
+
log('๐ Choose your profile:', 'blue');
|
|
60
|
+
console.log('');
|
|
61
|
+
log(' 1. Minimal Essential rules only (great for getting started)');
|
|
62
|
+
log(' 2. Standard Recommended baseline โญ (most popular)');
|
|
63
|
+
log(' 3. Strict All rules enforced (maximum code quality)');
|
|
64
|
+
log(' 4. Accessibility WCAG 2.1+ focused (a11y priority)');
|
|
65
|
+
console.log('');
|
|
66
|
+
|
|
67
|
+
const answer = await question('Enter number (1-4) [default: 2]:');
|
|
68
|
+
const choice = answer.trim() || '2';
|
|
69
|
+
|
|
70
|
+
const profiles = {
|
|
71
|
+
'1': 'minimal',
|
|
72
|
+
'2': 'standard',
|
|
73
|
+
'3': 'strict',
|
|
74
|
+
'4': 'accessibility'
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return profiles[choice] || 'standard';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function selectTool() {
|
|
81
|
+
const detected = detectAITool();
|
|
82
|
+
|
|
83
|
+
if (detected) {
|
|
84
|
+
console.log('');
|
|
85
|
+
log(`โ
Detected: ${detected.charAt(0).toUpperCase() + detected.slice(1)}`, 'green');
|
|
86
|
+
const answer = await question(`Continue with ${detected}? (Y/n):`);
|
|
87
|
+
if (!answer.trim() || answer.toLowerCase() === 'y') {
|
|
88
|
+
return detected;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log('');
|
|
93
|
+
log('๐ ๏ธ Select your AI coding tool:', 'blue');
|
|
94
|
+
console.log('');
|
|
95
|
+
log(' 1. Cursor (.cursorrules)');
|
|
96
|
+
log(' 2. Windsurf (.windsurfrules)');
|
|
97
|
+
log(' 3. Antigravity (.agent/rules/)');
|
|
98
|
+
log(' 4. GitHub Copilot (.github/copilot-instructions.md)');
|
|
99
|
+
log(' 5. Universal Works with most tools โญ');
|
|
100
|
+
console.log('');
|
|
101
|
+
|
|
102
|
+
const answer = await question('Enter number (1-5) [default: 5]:');
|
|
103
|
+
const choice = answer.trim() || '5';
|
|
104
|
+
|
|
105
|
+
const tools = {
|
|
106
|
+
'1': 'cursor',
|
|
107
|
+
'2': 'windsurf',
|
|
108
|
+
'3': 'antigravity',
|
|
109
|
+
'4': 'copilot',
|
|
110
|
+
'5': 'universal'
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return tools[choice] || 'universal';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function copyTemplate(profile, tool) {
|
|
117
|
+
const templatesDir = path.join(__dirname, '..', 'templates');
|
|
118
|
+
const cwd = process.cwd();
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
if (tool === 'antigravity') {
|
|
122
|
+
// Copy Antigravity .agent/rules/ structure
|
|
123
|
+
const sourceDir = path.join(templatesDir, 'antigravity', profile, '.agent', 'rules');
|
|
124
|
+
const targetDir = path.join(cwd, '.agent', 'rules');
|
|
125
|
+
|
|
126
|
+
if (!fs.existsSync(targetDir)) {
|
|
127
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const files = fs.readdirSync(sourceDir);
|
|
131
|
+
files.forEach(file => {
|
|
132
|
+
fs.copyFileSync(
|
|
133
|
+
path.join(sourceDir, file),
|
|
134
|
+
path.join(targetDir, file)
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
console.log('');
|
|
139
|
+
log(`โจ Created .agent/rules/ with ${profile} profile`, 'green');
|
|
140
|
+
log(` Files: ${files.join(', ')}`, 'cyan');
|
|
141
|
+
|
|
142
|
+
} else if (tool === 'copilot') {
|
|
143
|
+
const sourceFile = path.join(templatesDir, profile, '.cursorrules');
|
|
144
|
+
const targetDir = path.join(cwd, '.github');
|
|
145
|
+
const targetFile = path.join(targetDir, 'copilot-instructions.md');
|
|
146
|
+
|
|
147
|
+
if (!fs.existsSync(targetDir)) {
|
|
148
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
fs.copyFileSync(sourceFile, targetFile);
|
|
152
|
+
|
|
153
|
+
console.log('');
|
|
154
|
+
log(`โจ Created .github/copilot-instructions.md with ${profile} profile`, 'green');
|
|
155
|
+
|
|
156
|
+
} else {
|
|
157
|
+
const sourceFile = path.join(templatesDir, profile, '.cursorrules');
|
|
158
|
+
let targetFile;
|
|
159
|
+
|
|
160
|
+
if (tool === 'windsurf') {
|
|
161
|
+
targetFile = path.join(cwd, '.windsurfrules');
|
|
162
|
+
} else {
|
|
163
|
+
targetFile = path.join(cwd, '.cursorrules');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
fs.copyFileSync(sourceFile, targetFile);
|
|
167
|
+
|
|
168
|
+
console.log('');
|
|
169
|
+
log(`โจ Created ${path.basename(targetFile)} with ${profile} profile`, 'green');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return true;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.log('');
|
|
175
|
+
log(`โ Error: ${error.message}`, 'red');
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function showNextSteps(tool, profile) {
|
|
181
|
+
console.log('');
|
|
182
|
+
log('๐ Setup complete!', 'green');
|
|
183
|
+
console.log('');
|
|
184
|
+
log('Next steps:', 'bright');
|
|
185
|
+
log(' 1. Review your rules file(s)');
|
|
186
|
+
log(' 2. Customize for your project needs');
|
|
187
|
+
log(' 3. Start coding with your AI agent!');
|
|
188
|
+
console.log('');
|
|
189
|
+
|
|
190
|
+
log('๐ Documentation:', 'blue');
|
|
191
|
+
log(' https://github.com/netshdev/codingwithagent');
|
|
192
|
+
console.log('');
|
|
193
|
+
|
|
194
|
+
if (tool === 'antigravity') {
|
|
195
|
+
log('๐ก Tip: Antigravity auto-loads rules from .agent/rules/', 'yellow');
|
|
196
|
+
} else if (tool === 'copilot') {
|
|
197
|
+
log('๐ก Tip: Copilot reads instructions from .github/copilot-instructions.md', 'yellow');
|
|
198
|
+
} else {
|
|
199
|
+
log('๐ก Tip: Your AI agent will automatically use these rules', 'yellow');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log('');
|
|
203
|
+
log('โญ Star us on GitHub if this helped!', 'cyan');
|
|
204
|
+
console.log('');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function main() {
|
|
208
|
+
try {
|
|
209
|
+
header();
|
|
210
|
+
|
|
211
|
+
const profile = await selectProfile();
|
|
212
|
+
const tool = await selectTool();
|
|
213
|
+
|
|
214
|
+
console.log('');
|
|
215
|
+
log('โ๏ธ Installing...', 'cyan');
|
|
216
|
+
|
|
217
|
+
const success = copyTemplate(profile, tool);
|
|
218
|
+
|
|
219
|
+
if (success) {
|
|
220
|
+
showNextSteps(tool, profile);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
rl.close();
|
|
224
|
+
process.exit(success ? 0 : 1);
|
|
225
|
+
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.log('');
|
|
228
|
+
log(`โ Error: ${error.message}`, 'red');
|
|
229
|
+
log('Please report this issue on GitHub', 'yellow');
|
|
230
|
+
rl.close();
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Handle command line args
|
|
236
|
+
const args = process.argv.slice(2);
|
|
237
|
+
|
|
238
|
+
if (args.length === 0 || args[0] === 'init') {
|
|
239
|
+
main();
|
|
240
|
+
} else if (args[0] === '--version' || args[0] === '-v') {
|
|
241
|
+
const packageJson = require('../package.json');
|
|
242
|
+
console.log(packageJson.version);
|
|
243
|
+
process.exit(0);
|
|
244
|
+
} else if (args[0] === '--help' || args[0] === '-h') {
|
|
245
|
+
console.log('');
|
|
246
|
+
log('Usage: npx codingwithagent [command]', 'cyan');
|
|
247
|
+
console.log('');
|
|
248
|
+
log('Commands:');
|
|
249
|
+
log(' init Initialize standards (default)');
|
|
250
|
+
log(' --version, -v Show version');
|
|
251
|
+
log(' --help, -h Show this help');
|
|
252
|
+
console.log('');
|
|
253
|
+
process.exit(0);
|
|
254
|
+
} else {
|
|
255
|
+
log('Unknown command. Use --help for usage information.', 'red');
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codingwithagent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Production-ready coding standards for AI coding agents. Works with Cursor, Windsurf, Antigravity, and GitHub Copilot.",
|
|
5
|
+
"main": "bin/init.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"codingwithagent": "./bin/init.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"prepublishOnly": "node -e \"console.log('Publishing codingwithagent...')\"",
|
|
12
|
+
"postinstall": "echo 'Run: npx codingwithagent init'"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/netshdev/codingwithagent.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"ai",
|
|
20
|
+
"coding-standards",
|
|
21
|
+
"cursor",
|
|
22
|
+
"windsurf",
|
|
23
|
+
"antigravity",
|
|
24
|
+
"copilot",
|
|
25
|
+
"accessibility",
|
|
26
|
+
"wcag",
|
|
27
|
+
"react",
|
|
28
|
+
"typescript",
|
|
29
|
+
"code-quality",
|
|
30
|
+
"best-practices",
|
|
31
|
+
"a11y",
|
|
32
|
+
"linting",
|
|
33
|
+
"development",
|
|
34
|
+
"productivity",
|
|
35
|
+
"cursorrules",
|
|
36
|
+
"windsurfrules"
|
|
37
|
+
],
|
|
38
|
+
"author": "Nitish Kafle <kaflenit@gmail.com>",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/netshdev/codingwithagent/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/netshdev/codingwithagent#readme",
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=14.0.0"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"bin/",
|
|
49
|
+
"templates/",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE",
|
|
52
|
+
"CHANGELOG.md"
|
|
53
|
+
],
|
|
54
|
+
"dependencies": {},
|
|
55
|
+
"devDependencies": {}
|
|
56
|
+
}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Agentic Code Standards - Accessibility-Focused Profile
|
|
2
|
+
|
|
3
|
+
# Version: 1.0.0
|
|
4
|
+
|
|
5
|
+
# Profile: WCAG 2.1+ priority - accessibility first
|
|
6
|
+
|
|
7
|
+
## Mission
|
|
8
|
+
|
|
9
|
+
Every user, regardless of ability, deserves equal access to your application. This profile prioritizes accessibility above all else while maintaining code quality.
|
|
10
|
+
|
|
11
|
+
## WCAG 2.1 Level AA Compliance (Minimum)
|
|
12
|
+
|
|
13
|
+
### Perceivable - Everyone Can "See" This
|
|
14
|
+
|
|
15
|
+
#### Text Alternatives
|
|
16
|
+
|
|
17
|
+
- ALL images MUST have alt text (or alt="" if decorative)
|
|
18
|
+
- Complex images (charts, diagrams) MUST have detailed descriptions
|
|
19
|
+
- Icons with meaning MUST have accessible labels
|
|
20
|
+
- Decorative images MUST have empty alt attributes
|
|
21
|
+
|
|
22
|
+
#### Multimedia
|
|
23
|
+
|
|
24
|
+
- ALL videos MUST have captions
|
|
25
|
+
- ALL audio content MUST have transcripts
|
|
26
|
+
- Captions MUST be accurate and synchronized
|
|
27
|
+
- Audio descriptions MUST be provided for visual-only content
|
|
28
|
+
|
|
29
|
+
#### Adaptable Content
|
|
30
|
+
|
|
31
|
+
- Use semantic HTML (nav, main, header, footer, article, section)
|
|
32
|
+
- Proper heading hierarchy (h1 โ h2 โ h3, no skipping)
|
|
33
|
+
- Meaningful landmarks for screen reader navigation
|
|
34
|
+
- Reading order MUST match visual order
|
|
35
|
+
- Content MUST be understandable when CSS is disabled
|
|
36
|
+
|
|
37
|
+
#### Distinguishable
|
|
38
|
+
|
|
39
|
+
- **Color Contrast Requirements:**
|
|
40
|
+
- Normal text: 4.5:1 minimum (7:1 for AAA)
|
|
41
|
+
- Large text (18pt+ or 14pt+ bold): 3:1 minimum
|
|
42
|
+
- UI components and graphics: 3:1 minimum
|
|
43
|
+
- Use Color Contrast Analyzer tool
|
|
44
|
+
- NEVER use color alone to convey information
|
|
45
|
+
- Add patterns, icons, or text in addition to color
|
|
46
|
+
- Audio MUST have option to pause/stop
|
|
47
|
+
- No auto-playing audio >3 seconds
|
|
48
|
+
|
|
49
|
+
### Operable - Everyone Can Use This
|
|
50
|
+
|
|
51
|
+
#### Keyboard Accessible
|
|
52
|
+
|
|
53
|
+
- ALL functionality MUST work with keyboard only
|
|
54
|
+
- Visible focus indicators REQUIRED (2px outline minimum)
|
|
55
|
+
- Focus order MUST be logical and intuitive
|
|
56
|
+
- NO keyboard traps (user can always escape)
|
|
57
|
+
- NEVER use `tabIndex > 0`
|
|
58
|
+
- Support standard keys: Tab, Enter, Space, Escape, Arrow keys
|
|
59
|
+
|
|
60
|
+
#### Enough Time
|
|
61
|
+
|
|
62
|
+
- NO time limits unless:
|
|
63
|
+
- User can turn off the limit
|
|
64
|
+
- User can adjust limit to 10x default
|
|
65
|
+
- User is warned and given 20 seconds to extend
|
|
66
|
+
- Provide pause/stop for moving content
|
|
67
|
+
- Auto-updates MUST have controls
|
|
68
|
+
|
|
69
|
+
#### Seizures and Physical Reactions
|
|
70
|
+
|
|
71
|
+
- NOTHING flashes more than 3 times per second
|
|
72
|
+
- Avoid large flashing areas
|
|
73
|
+
- Provide warnings for flashing content
|
|
74
|
+
- Animation MUST respect `prefers-reduced-motion`
|
|
75
|
+
|
|
76
|
+
#### Navigable
|
|
77
|
+
|
|
78
|
+
- Skip navigation links for keyboard users
|
|
79
|
+
- Descriptive page titles
|
|
80
|
+
- Meaningful link text (avoid "click here", "read more")
|
|
81
|
+
- Multiple ways to find pages (search, sitemap, navigation)
|
|
82
|
+
- Clear focus indicators
|
|
83
|
+
- Breadcrumbs for complex navigation
|
|
84
|
+
|
|
85
|
+
### Understandable - Everyone Can Comprehend This
|
|
86
|
+
|
|
87
|
+
#### Readable
|
|
88
|
+
|
|
89
|
+
- Set language of page: `<html lang="en">`
|
|
90
|
+
- Set language of parts: `<span lang="es">Hola</span>`
|
|
91
|
+
- Use plain language (8th grade reading level or below)
|
|
92
|
+
- Define unusual words and abbreviations
|
|
93
|
+
- Expansion available for abbreviations
|
|
94
|
+
|
|
95
|
+
#### Predictable
|
|
96
|
+
|
|
97
|
+
- Consistent navigation across pages
|
|
98
|
+
- Consistent identification (icons, buttons)
|
|
99
|
+
- NO automatic context changes on focus
|
|
100
|
+
- NO automatic context changes on input (without warning)
|
|
101
|
+
- Forms submit ONLY on explicit action
|
|
102
|
+
|
|
103
|
+
#### Input Assistance
|
|
104
|
+
|
|
105
|
+
- Labels for ALL form inputs
|
|
106
|
+
- Clear error messages with suggestions
|
|
107
|
+
- Error prevention for legal/financial/data transactions
|
|
108
|
+
- Confirmation pages for submissions
|
|
109
|
+
- Ability to review and correct before final submission
|
|
110
|
+
|
|
111
|
+
### Robust - All Devices Can Use This
|
|
112
|
+
|
|
113
|
+
#### Compatible
|
|
114
|
+
|
|
115
|
+
- Valid HTML (pass W3C validator)
|
|
116
|
+
- Proper ARIA attributes when needed
|
|
117
|
+
- Name, role, value for all UI components
|
|
118
|
+
- Status messages programmatically determinable
|
|
119
|
+
- Works with assistive technologies
|
|
120
|
+
- Test with NVDA, JAWS, VoiceOver, TalkBack
|
|
121
|
+
|
|
122
|
+
## ARIA - Use Carefully
|
|
123
|
+
|
|
124
|
+
### When to Use ARIA
|
|
125
|
+
|
|
126
|
+
- Only when semantic HTML isn't sufficient
|
|
127
|
+
- Custom widgets (tabs, accordions, modals)
|
|
128
|
+
- Live regions for dynamic content
|
|
129
|
+
- Relationship indicators
|
|
130
|
+
|
|
131
|
+
### ARIA Rules
|
|
132
|
+
|
|
133
|
+
1. First Rule of ARIA: Don't use ARIA (use semantic HTML first)
|
|
134
|
+
2. Never change semantic meaning
|
|
135
|
+
3. All interactive ARIA controls must be keyboard accessible
|
|
136
|
+
4. Don't hide visible and actionable elements from screen readers
|
|
137
|
+
5. All interactive elements must have an accessible name
|
|
138
|
+
|
|
139
|
+
### Common ARIA Patterns
|
|
140
|
+
|
|
141
|
+
- `role="button"` - Only if you can't use `<button>`
|
|
142
|
+
- `aria-label` - Provide name when visual label isn't present
|
|
143
|
+
- `aria-labelledby` - Associate existing label
|
|
144
|
+
- `aria-describedby` - Additional description
|
|
145
|
+
- `aria-live` - Announce dynamic content changes
|
|
146
|
+
- `aria-expanded` - State of collapsible content
|
|
147
|
+
- `aria-hidden="true"` - Hide decorative elements
|
|
148
|
+
|
|
149
|
+
## Forms Accessibility
|
|
150
|
+
|
|
151
|
+
### Form Field Requirements
|
|
152
|
+
|
|
153
|
+
- ALL inputs MUST have associated `<label>` elements
|
|
154
|
+
- Use `<label for="inputId">` or wrap input
|
|
155
|
+
- Required fields MUST be indicated (not just with color/asterisk)
|
|
156
|
+
- Error messages MUST be programmatically associated
|
|
157
|
+
- Validation MUST happen on blur or submit, not on input
|
|
158
|
+
|
|
159
|
+
### Form Patterns
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
// Good: Associated label
|
|
163
|
+
<label htmlFor="email">Email Address *</label>
|
|
164
|
+
<input id="email" type="email" required aria-describedby="email-help" />
|
|
165
|
+
<small id="email-help">We'll never share your email</small>
|
|
166
|
+
|
|
167
|
+
// Good: Error handling
|
|
168
|
+
<input
|
|
169
|
+
id="email"
|
|
170
|
+
type="email"
|
|
171
|
+
aria-invalid={hasError}
|
|
172
|
+
aria-describedby="email-error"
|
|
173
|
+
/>
|
|
174
|
+
{hasError && <p id="email-error" role="alert">Please enter a valid email</p>}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Form Validation
|
|
178
|
+
|
|
179
|
+
- Inline validation on blur
|
|
180
|
+
- Clear error messages with solutions
|
|
181
|
+
- Error summary at top of form
|
|
182
|
+
- Focus management to first error
|
|
183
|
+
- Success confirmation
|
|
184
|
+
|
|
185
|
+
## React Accessibility
|
|
186
|
+
|
|
187
|
+
### Component Requirements
|
|
188
|
+
|
|
189
|
+
- Semantic HTML elements preferred over divs
|
|
190
|
+
- Button elements for actions, links for navigation
|
|
191
|
+
- Proper heading hierarchy maintained
|
|
192
|
+
- Focus management in modals and dynamic content
|
|
193
|
+
- Announce dynamic content with aria-live
|
|
194
|
+
|
|
195
|
+
### Focus Management
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
// Good: Focus management in modal
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
if (isOpen) {
|
|
201
|
+
modalRef.current?.focus();
|
|
202
|
+
}
|
|
203
|
+
}, [isOpen]);
|
|
204
|
+
|
|
205
|
+
// Good: Trap focus in modal
|
|
206
|
+
const handleKeyDown = (e) => {
|
|
207
|
+
if (e.key === "Escape") closeModal();
|
|
208
|
+
if (e.key === "Tab") trapFocus(e);
|
|
209
|
+
};
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Live Regions
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
// Good: Announce loading state
|
|
216
|
+
<div role="status" aria-live="polite" aria-atomic="true">
|
|
217
|
+
{isLoading ? "Loading..." : `${results.length} results found`}
|
|
218
|
+
</div>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Testing Requirements
|
|
222
|
+
|
|
223
|
+
### Automated Testing
|
|
224
|
+
|
|
225
|
+
- axe-core or jest-axe in unit tests
|
|
226
|
+
- Lighthouse accessibility audit (score 100)
|
|
227
|
+
- pa11y or similar in CI/CD
|
|
228
|
+
- ESLint jsx-a11y plugin enabled
|
|
229
|
+
|
|
230
|
+
### Manual Testing
|
|
231
|
+
|
|
232
|
+
1. Keyboard navigation (Tab, Enter, Space, Escape)
|
|
233
|
+
2. Screen reader testing:
|
|
234
|
+
- NVDA (Windows - free)
|
|
235
|
+
- JAWS (Windows - paid)
|
|
236
|
+
- VoiceOver (Mac/iOS - built-in)
|
|
237
|
+
- TalkBack (Android - built-in)
|
|
238
|
+
3. Color contrast analyzer
|
|
239
|
+
4. Zoom to 200% (text must remain readable)
|
|
240
|
+
5. Browser with CSS disabled
|
|
241
|
+
6. prefers-reduced-motion testing
|
|
242
|
+
|
|
243
|
+
### Testing Checklist
|
|
244
|
+
|
|
245
|
+
- [ ] All functionality keyboard accessible
|
|
246
|
+
- [ ] Visible focus indicators
|
|
247
|
+
- [ ] Logical focus order
|
|
248
|
+
- [ ] Screen reader announces content correctly
|
|
249
|
+
- [ ] Color contrast passes
|
|
250
|
+
- [ ] Alt text for images
|
|
251
|
+
- [ ] Form labels associated
|
|
252
|
+
- [ ] Error messages clear
|
|
253
|
+
- [ ] No automatic timeouts
|
|
254
|
+
- [ ] No flashing content
|
|
255
|
+
- [ ] Semantic HTML used
|
|
256
|
+
- [ ] Zoom to 200% works
|
|
257
|
+
|
|
258
|
+
## Code Examples
|
|
259
|
+
|
|
260
|
+
### Accessible Button
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
// Good: Semantic button
|
|
264
|
+
<button onClick={handleClick} aria-pressed={isPressed}>
|
|
265
|
+
Toggle {isPressed ? 'On' : 'Off'}
|
|
266
|
+
</button>
|
|
267
|
+
|
|
268
|
+
// Bad: Div as button
|
|
269
|
+
<div onClick={handleClick}>Click me</div>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Accessible Modal
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
const Modal = ({ isOpen, onClose, children }) => {
|
|
276
|
+
const modalRef = useRef();
|
|
277
|
+
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
if (isOpen) {
|
|
280
|
+
modalRef.current?.focus();
|
|
281
|
+
}
|
|
282
|
+
}, [isOpen]);
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<div
|
|
286
|
+
role="dialog"
|
|
287
|
+
aria-modal="true"
|
|
288
|
+
aria-labelledby="modal-title"
|
|
289
|
+
ref={modalRef}
|
|
290
|
+
tabIndex={-1}
|
|
291
|
+
onKeyDown={(e) => e.key === "Escape" && onClose()}
|
|
292
|
+
>
|
|
293
|
+
<h2 id="modal-title">Modal Title</h2>
|
|
294
|
+
{children}
|
|
295
|
+
<button onClick={onClose}>Close</button>
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
};
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Accessible Navigation
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
<nav aria-label="Main navigation">
|
|
305
|
+
<ul>
|
|
306
|
+
<li>
|
|
307
|
+
<a href="/" aria-current={isHome && "page"}>
|
|
308
|
+
Home
|
|
309
|
+
</a>
|
|
310
|
+
</li>
|
|
311
|
+
<li>
|
|
312
|
+
<a href="/about">About</a>
|
|
313
|
+
</li>
|
|
314
|
+
<li>
|
|
315
|
+
<a href="/contact">Contact</a>
|
|
316
|
+
</li>
|
|
317
|
+
</ul>
|
|
318
|
+
</nav>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Resources
|
|
322
|
+
|
|
323
|
+
### Guidelines
|
|
324
|
+
|
|
325
|
+
- WCAG 2.1: https://www.w3.org/WAI/WCAG21/quickref/
|
|
326
|
+
- ARIA Authoring Practices: https://www.w3.org/WAI/ARIA/apg/
|
|
327
|
+
- WebAIM: https://webaim.org/
|
|
328
|
+
|
|
329
|
+
### Testing Tools
|
|
330
|
+
|
|
331
|
+
- axe DevTools: https://www.deque.com/axe/devtools/
|
|
332
|
+
- WAVE: https://wave.webaim.org/
|
|
333
|
+
- Color Contrast Analyzer: https://www.tpgi.com/color-contrast-checker/
|
|
334
|
+
|
|
335
|
+
### Screen Readers
|
|
336
|
+
|
|
337
|
+
- NVDA (free): https://www.nvaccess.org/
|
|
338
|
+
- VoiceOver: Built into Mac/iOS
|
|
339
|
+
- TalkBack: Built into Android
|
|
340
|
+
|
|
341
|
+
Accessibility is not optional.
|
|
342
|
+
Full documentation: https://github.com/netshdev/codingwithagent
|