cursor-kit-cli 1.2.0-beta → 1.2.0-beta.3
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/bin/cursor-reinstall-instance.sh +102 -0
- package/dist/cli.cjs +366 -69
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +367 -70
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +39 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +33 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/commands/docs.md +5 -3
- package/templates/commands/explain.md +5 -3
- package/templates/commands/fix.md +5 -3
- package/templates/commands/implement.md +5 -3
- package/templates/commands/refactor.md +5 -3
- package/templates/commands/review.md +5 -3
- package/templates/commands/test.md +5 -3
- package/templates/manifest.json +11 -8
- package/templates/rules/git.mdc +0 -2
- package/templates/rules/toc.mdc +17 -9
- package/templates/skills/aesthetic/SKILL.md +121 -0
- package/templates/skills/aesthetic/assets/design-guideline-template.md +163 -0
- package/templates/skills/aesthetic/assets/design-story-template.md +135 -0
- package/templates/skills/aesthetic/references/design-principles.md +62 -0
- package/templates/skills/aesthetic/references/design-resources.md +75 -0
- package/templates/skills/aesthetic/references/micro-interactions.md +53 -0
- package/templates/skills/aesthetic/references/storytelling-design.md +50 -0
- package/templates/skills/backend-development/SKILL.mdc +95 -0
- package/templates/skills/backend-development/references/backend-api-design.md +495 -0
- package/templates/skills/backend-development/references/backend-architecture.md +454 -0
- package/templates/skills/backend-development/references/backend-authentication.md +338 -0
- package/templates/skills/backend-development/references/backend-code-quality.md +659 -0
- package/templates/skills/backend-development/references/backend-debugging.md +904 -0
- package/templates/skills/backend-development/references/backend-devops.md +494 -0
- package/templates/skills/backend-development/references/backend-mindset.md +387 -0
- package/templates/skills/backend-development/references/backend-performance.md +397 -0
- package/templates/skills/backend-development/references/backend-security.md +290 -0
- package/templates/skills/backend-development/references/backend-technologies.md +256 -0
- package/templates/skills/backend-development/references/backend-testing.md +429 -0
- package/templates/skills/frontend-design/SKILL.mdc +41 -0
- package/templates/skills/frontend-design/references/animejs.md +396 -0
- package/templates/skills/frontend-development/SKILL.mdc +399 -0
- package/templates/skills/frontend-development/resources/common-patterns.md +331 -0
- package/templates/skills/frontend-development/resources/complete-examples.md +872 -0
- package/templates/skills/frontend-development/resources/component-patterns.md +502 -0
- package/templates/skills/frontend-development/resources/data-fetching.md +767 -0
- package/templates/skills/frontend-development/resources/file-organization.md +502 -0
- package/templates/skills/frontend-development/resources/loading-and-error-states.md +501 -0
- package/templates/skills/frontend-development/resources/performance.md +406 -0
- package/templates/skills/frontend-development/resources/routing-guide.md +364 -0
- package/templates/skills/frontend-development/resources/styling-guide.md +428 -0
- package/templates/skills/frontend-development/resources/typescript-standards.md +418 -0
- package/templates/skills/problem-solving/SKILL.mdc +96 -0
- package/templates/skills/problem-solving/references/attribution.md +69 -0
- package/templates/skills/problem-solving/references/collision-zone-thinking.md +79 -0
- package/templates/skills/problem-solving/references/inversion-exercise.md +91 -0
- package/templates/skills/problem-solving/references/meta-pattern-recognition.md +87 -0
- package/templates/skills/problem-solving/references/scale-game.md +95 -0
- package/templates/skills/problem-solving/references/simplification-cascades.md +80 -0
- package/templates/skills/problem-solving/references/when-stuck.md +72 -0
- package/templates/skills/research/SKILL.mdc +168 -0
- package/templates/skills/sequential-thinking/.env.example +8 -0
- package/templates/skills/sequential-thinking/README.md +183 -0
- package/templates/skills/sequential-thinking/SKILL.mdc +94 -0
- package/templates/skills/sequential-thinking/package.json +31 -0
- package/templates/skills/sequential-thinking/references/advanced-strategies.md +79 -0
- package/templates/skills/sequential-thinking/references/advanced-techniques.md +76 -0
- package/templates/skills/sequential-thinking/references/core-patterns.md +95 -0
- package/templates/skills/sequential-thinking/references/examples-api.md +88 -0
- package/templates/skills/sequential-thinking/references/examples-architecture.md +94 -0
- package/templates/skills/sequential-thinking/references/examples-debug.md +90 -0
- package/templates/skills/sequential-thinking/scripts/format-thought.js +159 -0
- package/templates/skills/sequential-thinking/scripts/process-thought.js +236 -0
- package/templates/skills/sequential-thinking/tests/format-thought.test.js +133 -0
- package/templates/skills/sequential-thinking/tests/process-thought.test.js +215 -0
- package/templates/skills/ui-styling/LICENSE.txt +202 -0
- package/templates/skills/ui-styling/SKILL.mdc +321 -0
- package/templates/skills/ui-styling/references/canvas-design-system.md +320 -0
- package/templates/skills/ui-styling/references/shadcn-accessibility.md +471 -0
- package/templates/skills/ui-styling/references/shadcn-components.md +424 -0
- package/templates/skills/ui-styling/references/shadcn-theming.md +373 -0
- package/templates/skills/ui-styling/references/tailwind-customization.md +483 -0
- package/templates/skills/ui-styling/references/tailwind-responsive.md +382 -0
- package/templates/skills/ui-styling/references/tailwind-utilities.md +455 -0
- package/templates/rules/frontend-design.mdc +0 -48
- package/templates/rules/performance.mdc +0 -54
- package/templates/rules/react.mdc +0 -58
- package/templates/rules/security.mdc +0 -50
- package/templates/rules/testing.mdc +0 -54
- package/templates/rules/typescript.mdc +0 -36
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
# shadcn/ui Accessibility Patterns
|
|
2
|
+
|
|
3
|
+
ARIA patterns, keyboard navigation, screen reader support, and accessible component usage.
|
|
4
|
+
|
|
5
|
+
## Foundation: Radix UI Primitives
|
|
6
|
+
|
|
7
|
+
shadcn/ui built on Radix UI primitives - unstyled, accessible components following WAI-ARIA design patterns.
|
|
8
|
+
|
|
9
|
+
Benefits:
|
|
10
|
+
- Keyboard navigation built-in
|
|
11
|
+
- Screen reader announcements
|
|
12
|
+
- Focus management
|
|
13
|
+
- ARIA attributes automatically applied
|
|
14
|
+
- Tested against accessibility standards
|
|
15
|
+
|
|
16
|
+
## Keyboard Navigation
|
|
17
|
+
|
|
18
|
+
### Focus Management
|
|
19
|
+
|
|
20
|
+
**Focus visible states:**
|
|
21
|
+
```tsx
|
|
22
|
+
<Button className="focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
|
|
23
|
+
Accessible Button
|
|
24
|
+
</Button>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Skip to content:**
|
|
28
|
+
```tsx
|
|
29
|
+
<a href="#main-content" className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2">
|
|
30
|
+
Skip to content
|
|
31
|
+
</a>
|
|
32
|
+
|
|
33
|
+
<main id="main-content">
|
|
34
|
+
{/* Content */}
|
|
35
|
+
</main>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Dialog/Modal Navigation
|
|
39
|
+
|
|
40
|
+
Dialogs trap focus automatically via Radix Dialog primitive:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"
|
|
44
|
+
|
|
45
|
+
<Dialog>
|
|
46
|
+
<DialogTrigger>Open</DialogTrigger>
|
|
47
|
+
<DialogContent>
|
|
48
|
+
{/* Focus trapped here */}
|
|
49
|
+
<input /> {/* Auto-focused */}
|
|
50
|
+
<Button>Action</Button>
|
|
51
|
+
{/* Esc to close, Tab to navigate */}
|
|
52
|
+
</DialogContent>
|
|
53
|
+
</Dialog>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Features:
|
|
57
|
+
- Focus trapped within dialog
|
|
58
|
+
- Esc key closes
|
|
59
|
+
- Tab cycles through focusable elements
|
|
60
|
+
- Focus returns to trigger on close
|
|
61
|
+
|
|
62
|
+
### Dropdown/Menu Navigation
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
|
66
|
+
|
|
67
|
+
<DropdownMenu>
|
|
68
|
+
<DropdownMenuTrigger>Open</DropdownMenuTrigger>
|
|
69
|
+
<DropdownMenuContent>
|
|
70
|
+
<DropdownMenuItem>Profile</DropdownMenuItem>
|
|
71
|
+
<DropdownMenuItem>Settings</DropdownMenuItem>
|
|
72
|
+
<DropdownMenuItem>Logout</DropdownMenuItem>
|
|
73
|
+
</DropdownMenuContent>
|
|
74
|
+
</DropdownMenu>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Keyboard shortcuts:
|
|
78
|
+
- `Space/Enter`: Open menu
|
|
79
|
+
- `Arrow Up/Down`: Navigate items
|
|
80
|
+
- `Esc`: Close menu
|
|
81
|
+
- `Tab`: Close and move focus
|
|
82
|
+
|
|
83
|
+
### Command Palette Navigation
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { Command } from "@/components/ui/command"
|
|
87
|
+
|
|
88
|
+
<Command>
|
|
89
|
+
<CommandInput placeholder="Search..." />
|
|
90
|
+
<CommandList>
|
|
91
|
+
<CommandGroup heading="Suggestions">
|
|
92
|
+
<CommandItem>Calendar</CommandItem>
|
|
93
|
+
<CommandItem>Search</CommandItem>
|
|
94
|
+
</CommandGroup>
|
|
95
|
+
</CommandList>
|
|
96
|
+
</Command>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Features:
|
|
100
|
+
- Type to filter
|
|
101
|
+
- Arrow keys to navigate
|
|
102
|
+
- Enter to select
|
|
103
|
+
- Esc to close
|
|
104
|
+
|
|
105
|
+
## Screen Reader Support
|
|
106
|
+
|
|
107
|
+
### Semantic HTML
|
|
108
|
+
|
|
109
|
+
Use proper HTML elements:
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
// Good: Semantic HTML
|
|
113
|
+
<button>Click me</button>
|
|
114
|
+
<nav><a href="/">Home</a></nav>
|
|
115
|
+
|
|
116
|
+
// Avoid: Div soup
|
|
117
|
+
<div onClick={handler}>Click me</div>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### ARIA Labels
|
|
121
|
+
|
|
122
|
+
**Label interactive elements:**
|
|
123
|
+
```tsx
|
|
124
|
+
<Button aria-label="Close dialog">
|
|
125
|
+
<X className="h-4 w-4" />
|
|
126
|
+
</Button>
|
|
127
|
+
|
|
128
|
+
<Input aria-label="Email address" type="email" />
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Describe elements:**
|
|
132
|
+
```tsx
|
|
133
|
+
<Button aria-describedby="delete-description">
|
|
134
|
+
Delete Account
|
|
135
|
+
</Button>
|
|
136
|
+
<p id="delete-description" className="sr-only">
|
|
137
|
+
This action permanently deletes your account and cannot be undone
|
|
138
|
+
</p>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Screen Reader Only Text
|
|
142
|
+
|
|
143
|
+
Use `sr-only` class for screen reader only content:
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
<Button>
|
|
147
|
+
<Trash className="h-4 w-4" />
|
|
148
|
+
<span className="sr-only">Delete item</span>
|
|
149
|
+
</Button>
|
|
150
|
+
|
|
151
|
+
// CSS for sr-only
|
|
152
|
+
.sr-only {
|
|
153
|
+
position: absolute;
|
|
154
|
+
width: 1px;
|
|
155
|
+
height: 1px;
|
|
156
|
+
padding: 0;
|
|
157
|
+
margin: -1px;
|
|
158
|
+
overflow: hidden;
|
|
159
|
+
clip: rect(0, 0, 0, 0);
|
|
160
|
+
white-space: nowrap;
|
|
161
|
+
border-width: 0;
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Live Regions
|
|
166
|
+
|
|
167
|
+
Announce dynamic content:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<div aria-live="polite" aria-atomic="true">
|
|
171
|
+
{message}
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
// For urgent updates
|
|
175
|
+
<div aria-live="assertive">
|
|
176
|
+
{error}
|
|
177
|
+
</div>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Toast component includes live region:
|
|
181
|
+
```tsx
|
|
182
|
+
const { toast } = useToast()
|
|
183
|
+
|
|
184
|
+
toast({
|
|
185
|
+
title: "Success",
|
|
186
|
+
description: "Profile updated"
|
|
187
|
+
})
|
|
188
|
+
// Announced to screen readers automatically
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Form Accessibility
|
|
192
|
+
|
|
193
|
+
### Labels and Descriptions
|
|
194
|
+
|
|
195
|
+
**Always label inputs:**
|
|
196
|
+
```tsx
|
|
197
|
+
import { Label } from "@/components/ui/label"
|
|
198
|
+
import { Input } from "@/components/ui/input"
|
|
199
|
+
|
|
200
|
+
<div>
|
|
201
|
+
<Label htmlFor="email">Email</Label>
|
|
202
|
+
<Input id="email" type="email" />
|
|
203
|
+
</div>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Add descriptions:**
|
|
207
|
+
```tsx
|
|
208
|
+
import { FormDescription, FormMessage } from "@/components/ui/form"
|
|
209
|
+
|
|
210
|
+
<FormItem>
|
|
211
|
+
<FormLabel>Username</FormLabel>
|
|
212
|
+
<FormControl>
|
|
213
|
+
<Input {...field} />
|
|
214
|
+
</FormControl>
|
|
215
|
+
<FormDescription>
|
|
216
|
+
Your public display name
|
|
217
|
+
</FormDescription>
|
|
218
|
+
<FormMessage /> {/* Error messages */}
|
|
219
|
+
</FormItem>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Error Handling
|
|
223
|
+
|
|
224
|
+
Announce errors to screen readers:
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
<FormField
|
|
228
|
+
control={form.control}
|
|
229
|
+
name="email"
|
|
230
|
+
render={({ field, fieldState }) => (
|
|
231
|
+
<FormItem>
|
|
232
|
+
<FormLabel>Email</FormLabel>
|
|
233
|
+
<FormControl>
|
|
234
|
+
<Input
|
|
235
|
+
{...field}
|
|
236
|
+
aria-invalid={!!fieldState.error}
|
|
237
|
+
aria-describedby={fieldState.error ? "email-error" : undefined}
|
|
238
|
+
/>
|
|
239
|
+
</FormControl>
|
|
240
|
+
<FormMessage id="email-error" />
|
|
241
|
+
</FormItem>
|
|
242
|
+
)}
|
|
243
|
+
/>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Required Fields
|
|
247
|
+
|
|
248
|
+
Indicate required fields:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
<Label htmlFor="name">
|
|
252
|
+
Name <span className="text-destructive">*</span>
|
|
253
|
+
<span className="sr-only">(required)</span>
|
|
254
|
+
</Label>
|
|
255
|
+
<Input id="name" required />
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Fieldset and Legend
|
|
259
|
+
|
|
260
|
+
Group related fields:
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
<fieldset>
|
|
264
|
+
<legend className="text-lg font-semibold mb-4">
|
|
265
|
+
Contact Information
|
|
266
|
+
</legend>
|
|
267
|
+
<div className="space-y-4">
|
|
268
|
+
<FormField name="email" />
|
|
269
|
+
<FormField name="phone" />
|
|
270
|
+
</div>
|
|
271
|
+
</fieldset>
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Component-Specific Patterns
|
|
275
|
+
|
|
276
|
+
### Accordion
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
import { Accordion } from "@/components/ui/accordion"
|
|
280
|
+
|
|
281
|
+
<Accordion type="single" collapsible>
|
|
282
|
+
<AccordionItem value="item-1">
|
|
283
|
+
<AccordionTrigger>
|
|
284
|
+
{/* Includes aria-expanded, aria-controls automatically */}
|
|
285
|
+
Is it accessible?
|
|
286
|
+
</AccordionTrigger>
|
|
287
|
+
<AccordionContent>
|
|
288
|
+
{/* Hidden when collapsed, announced when expanded */}
|
|
289
|
+
Yes. Follows WAI-ARIA design pattern.
|
|
290
|
+
</AccordionContent>
|
|
291
|
+
</AccordionItem>
|
|
292
|
+
</Accordion>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Tabs
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
import { Tabs } from "@/components/ui/tabs"
|
|
299
|
+
|
|
300
|
+
<Tabs defaultValue="account">
|
|
301
|
+
<TabsList role="tablist">
|
|
302
|
+
{/* Arrow keys navigate, Space/Enter activates */}
|
|
303
|
+
<TabsTrigger value="account">Account</TabsTrigger>
|
|
304
|
+
<TabsTrigger value="password">Password</TabsTrigger>
|
|
305
|
+
</TabsList>
|
|
306
|
+
<TabsContent value="account">
|
|
307
|
+
{/* Hidden unless selected, aria-labelledby links to trigger */}
|
|
308
|
+
Account content
|
|
309
|
+
</TabsContent>
|
|
310
|
+
</Tabs>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Select
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { Select } from "@/components/ui/select"
|
|
317
|
+
|
|
318
|
+
<Select>
|
|
319
|
+
<SelectTrigger aria-label="Choose theme">
|
|
320
|
+
<SelectValue placeholder="Theme" />
|
|
321
|
+
</SelectTrigger>
|
|
322
|
+
<SelectContent>
|
|
323
|
+
{/* Keyboard navigable, announced to screen readers */}
|
|
324
|
+
<SelectItem value="light">Light</SelectItem>
|
|
325
|
+
<SelectItem value="dark">Dark</SelectItem>
|
|
326
|
+
</SelectContent>
|
|
327
|
+
</Select>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Checkbox and Radio
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
import { Checkbox } from "@/components/ui/checkbox"
|
|
334
|
+
import { Label } from "@/components/ui/label"
|
|
335
|
+
|
|
336
|
+
<div className="flex items-center space-x-2">
|
|
337
|
+
<Checkbox id="terms" aria-describedby="terms-description" />
|
|
338
|
+
<Label htmlFor="terms">Accept terms</Label>
|
|
339
|
+
</div>
|
|
340
|
+
<p id="terms-description" className="text-sm text-muted-foreground">
|
|
341
|
+
You agree to our Terms of Service and Privacy Policy
|
|
342
|
+
</p>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Alert
|
|
346
|
+
|
|
347
|
+
```tsx
|
|
348
|
+
import { Alert } from "@/components/ui/alert"
|
|
349
|
+
|
|
350
|
+
<Alert role="alert">
|
|
351
|
+
{/* Announced immediately to screen readers */}
|
|
352
|
+
<AlertTitle>Error</AlertTitle>
|
|
353
|
+
<AlertDescription>
|
|
354
|
+
Your session has expired
|
|
355
|
+
</AlertDescription>
|
|
356
|
+
</Alert>
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Color Contrast
|
|
360
|
+
|
|
361
|
+
Ensure sufficient contrast between text and background.
|
|
362
|
+
|
|
363
|
+
**WCAG Requirements:**
|
|
364
|
+
- **AA**: 4.5:1 for normal text, 3:1 for large text
|
|
365
|
+
- **AAA**: 7:1 for normal text, 4.5:1 for large text
|
|
366
|
+
|
|
367
|
+
**Check defaults:**
|
|
368
|
+
```tsx
|
|
369
|
+
// Good: High contrast
|
|
370
|
+
<p className="text-gray-900 dark:text-gray-100">Text</p>
|
|
371
|
+
|
|
372
|
+
// Avoid: Low contrast
|
|
373
|
+
<p className="text-gray-400 dark:text-gray-600">Hard to read</p>
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Muted text:**
|
|
377
|
+
```tsx
|
|
378
|
+
// Use semantic muted foreground
|
|
379
|
+
<p className="text-muted-foreground">
|
|
380
|
+
Secondary text with accessible contrast
|
|
381
|
+
</p>
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Focus Indicators
|
|
385
|
+
|
|
386
|
+
Always provide visible focus indicators:
|
|
387
|
+
|
|
388
|
+
**Default focus ring:**
|
|
389
|
+
```tsx
|
|
390
|
+
<Button className="focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
|
|
391
|
+
Button
|
|
392
|
+
</Button>
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Custom focus styles:**
|
|
396
|
+
```tsx
|
|
397
|
+
<a href="#" className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:underline">
|
|
398
|
+
Link
|
|
399
|
+
</a>
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Don't remove focus styles:**
|
|
403
|
+
```tsx
|
|
404
|
+
// Avoid
|
|
405
|
+
<button className="focus:outline-none">Bad</button>
|
|
406
|
+
|
|
407
|
+
// Use focus-visible instead
|
|
408
|
+
<button className="focus-visible:ring-2">Good</button>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Motion and Animation
|
|
412
|
+
|
|
413
|
+
Respect reduced motion preference:
|
|
414
|
+
|
|
415
|
+
```css
|
|
416
|
+
@media (prefers-reduced-motion: reduce) {
|
|
417
|
+
* {
|
|
418
|
+
animation-duration: 0.01ms !important;
|
|
419
|
+
animation-iteration-count: 1 !important;
|
|
420
|
+
transition-duration: 0.01ms !important;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
In components:
|
|
426
|
+
```tsx
|
|
427
|
+
<div className="transition-all motion-reduce:transition-none">
|
|
428
|
+
Respects user preference
|
|
429
|
+
</div>
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Testing Checklist
|
|
433
|
+
|
|
434
|
+
- [ ] All interactive elements keyboard accessible
|
|
435
|
+
- [ ] Focus indicators visible
|
|
436
|
+
- [ ] Screen reader announces all content correctly
|
|
437
|
+
- [ ] Form errors announced and associated
|
|
438
|
+
- [ ] Color contrast meets WCAG AA
|
|
439
|
+
- [ ] Semantic HTML used
|
|
440
|
+
- [ ] ARIA labels provided for icon-only buttons
|
|
441
|
+
- [ ] Modal/dialog focus trap works
|
|
442
|
+
- [ ] Dropdown/select keyboard navigable
|
|
443
|
+
- [ ] Live regions announce updates
|
|
444
|
+
- [ ] Respects reduced motion preference
|
|
445
|
+
- [ ] Works with browser zoom up to 200%
|
|
446
|
+
- [ ] Tab order logical
|
|
447
|
+
- [ ] Skip links provided for navigation
|
|
448
|
+
|
|
449
|
+
## Tools
|
|
450
|
+
|
|
451
|
+
**Testing tools:**
|
|
452
|
+
- Lighthouse accessibility audit
|
|
453
|
+
- axe DevTools browser extension
|
|
454
|
+
- NVDA/JAWS screen readers
|
|
455
|
+
- Keyboard-only navigation testing
|
|
456
|
+
- Color contrast checkers (Contrast Ratio, WebAIM)
|
|
457
|
+
|
|
458
|
+
**Automated testing:**
|
|
459
|
+
```bash
|
|
460
|
+
npm install -D @axe-core/react
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
```tsx
|
|
464
|
+
import { useEffect } from 'react'
|
|
465
|
+
|
|
466
|
+
if (process.env.NODE_ENV === 'development') {
|
|
467
|
+
import('@axe-core/react').then((axe) => {
|
|
468
|
+
axe.default(React, ReactDOM, 1000)
|
|
469
|
+
})
|
|
470
|
+
}
|
|
471
|
+
```
|