cfsa-antigravity 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/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: accessibility-compliance
|
|
3
|
+
description: "Ensure WCAG 2.1/2.2 compliance across web applications. Use when asked to audit accessibility, add ARIA support, fix keyboard navigation, improve screen reader experience, or meet legal compliance (ADA, EAA, Section 508)."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Accessibility Compliance
|
|
8
|
+
|
|
9
|
+
Comprehensive accessibility reference based on WCAG 2.1/2.2 and WAI-ARIA Authoring Practices. Every web application must be usable by people with disabilities --- this is not a feature, it is a baseline requirement.
|
|
10
|
+
|
|
11
|
+
## WCAG Principles: POUR
|
|
12
|
+
|
|
13
|
+
| Principle | Description |
|
|
14
|
+
|-----------|-------------|
|
|
15
|
+
| **P**erceivable | Content can be perceived through different senses |
|
|
16
|
+
| **O**perable | Interface can be operated by all users (keyboard, voice, switch) |
|
|
17
|
+
| **U**nderstandable | Content and interface behavior are predictable and clear |
|
|
18
|
+
| **R**obust | Content works with current and future assistive technologies |
|
|
19
|
+
|
|
20
|
+
## Conformance Levels
|
|
21
|
+
|
|
22
|
+
| Level | Requirement | When to Target |
|
|
23
|
+
|-------|-------------|----------------|
|
|
24
|
+
| **A** | Minimum accessibility | Always --- these are non-negotiable barriers |
|
|
25
|
+
| **AA** | Standard compliance | Default target --- legal requirement in most jurisdictions (ADA, EAA) |
|
|
26
|
+
| **AAA** | Enhanced accessibility | Target for specific content (gov, healthcare, education) --- not realistic site-wide |
|
|
27
|
+
|
|
28
|
+
**Rule of thumb:** Target AA for all production code. Target AAA for text contrast and reading level when feasible.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Semantic HTML
|
|
33
|
+
|
|
34
|
+
Semantic HTML is the foundation. ARIA should supplement native semantics, never replace them.
|
|
35
|
+
|
|
36
|
+
### Document Landmarks
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<body>
|
|
40
|
+
<a href="#main-content" class="skip-link">Skip to main content</a>
|
|
41
|
+
|
|
42
|
+
<header>
|
|
43
|
+
<nav aria-label="Main navigation">
|
|
44
|
+
<ul>
|
|
45
|
+
<li><a href="/" aria-current="page">Home</a></li>
|
|
46
|
+
<li><a href="/products">Products</a></li>
|
|
47
|
+
<li><a href="/about">About</a></li>
|
|
48
|
+
</ul>
|
|
49
|
+
</nav>
|
|
50
|
+
</header>
|
|
51
|
+
|
|
52
|
+
<aside aria-label="Sidebar">
|
|
53
|
+
<!-- Secondary content -->
|
|
54
|
+
</aside>
|
|
55
|
+
|
|
56
|
+
<main id="main-content" tabindex="-1">
|
|
57
|
+
<h1>Page Title</h1>
|
|
58
|
+
<!-- Primary page content -->
|
|
59
|
+
</main>
|
|
60
|
+
|
|
61
|
+
<footer>
|
|
62
|
+
<nav aria-label="Footer navigation">
|
|
63
|
+
<!-- Footer links -->
|
|
64
|
+
</nav>
|
|
65
|
+
</footer>
|
|
66
|
+
</body>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Heading Hierarchy
|
|
70
|
+
|
|
71
|
+
Headings must follow a logical hierarchy. Never skip levels for visual styling.
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<!-- WRONG: skipped h2 -->
|
|
75
|
+
<h1>Dashboard</h1>
|
|
76
|
+
<h3>Recent Activity</h3>
|
|
77
|
+
|
|
78
|
+
<!-- CORRECT: logical hierarchy -->
|
|
79
|
+
<h1>Dashboard</h1>
|
|
80
|
+
<h2>Recent Activity</h2>
|
|
81
|
+
<h3>Today</h3>
|
|
82
|
+
<h3>This Week</h3>
|
|
83
|
+
<h2>Settings</h2>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Lists
|
|
87
|
+
|
|
88
|
+
Use semantic list elements for grouped content --- screen readers announce "list of N items."
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<!-- Navigation as list -->
|
|
92
|
+
<nav aria-label="Breadcrumb">
|
|
93
|
+
<ol>
|
|
94
|
+
<li><a href="/">Home</a></li>
|
|
95
|
+
<li><a href="/products">Products</a></li>
|
|
96
|
+
<li aria-current="page">Widget Pro</li>
|
|
97
|
+
</ol>
|
|
98
|
+
</nav>
|
|
99
|
+
|
|
100
|
+
<!-- Tag/chip groups as list -->
|
|
101
|
+
<ul aria-label="Applied filters" role="list">
|
|
102
|
+
<li>Category: Electronics <button aria-label="Remove filter: Electronics">x</button></li>
|
|
103
|
+
<li>Price: Under $50 <button aria-label="Remove filter: Price under $50">x</button></li>
|
|
104
|
+
</ul>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## ARIA Roles, States, and Properties
|
|
110
|
+
|
|
111
|
+
### The First Rule of ARIA
|
|
112
|
+
|
|
113
|
+
**Do not use ARIA if a native HTML element provides the same semantics.**
|
|
114
|
+
|
|
115
|
+
```html
|
|
116
|
+
<!-- WRONG: ARIA on a div -->
|
|
117
|
+
<div role="button" tabindex="0" onclick="submit()">Submit</div>
|
|
118
|
+
|
|
119
|
+
<!-- CORRECT: native button -->
|
|
120
|
+
<button type="submit">Submit</button>
|
|
121
|
+
|
|
122
|
+
<!-- WRONG: ARIA checkbox -->
|
|
123
|
+
<div role="checkbox" aria-checked="false" tabindex="0">Enable notifications</div>
|
|
124
|
+
|
|
125
|
+
<!-- CORRECT: native checkbox -->
|
|
126
|
+
<label>
|
|
127
|
+
<input type="checkbox" name="notifications" />
|
|
128
|
+
Enable notifications
|
|
129
|
+
</label>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### When ARIA IS Needed
|
|
133
|
+
|
|
134
|
+
Use ARIA for custom widgets that have no native HTML equivalent.
|
|
135
|
+
|
|
136
|
+
**Tabs:**
|
|
137
|
+
```html
|
|
138
|
+
<div role="tablist" aria-label="Account settings">
|
|
139
|
+
<button role="tab" id="tab-profile" aria-selected="true"
|
|
140
|
+
aria-controls="panel-profile">Profile</button>
|
|
141
|
+
<button role="tab" id="tab-security" aria-selected="false"
|
|
142
|
+
aria-controls="panel-security" tabindex="-1">Security</button>
|
|
143
|
+
<button role="tab" id="tab-billing" aria-selected="false"
|
|
144
|
+
aria-controls="panel-billing" tabindex="-1">Billing</button>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div role="tabpanel" id="panel-profile" aria-labelledby="tab-profile">
|
|
148
|
+
<!-- Profile content -->
|
|
149
|
+
</div>
|
|
150
|
+
<div role="tabpanel" id="panel-security" aria-labelledby="tab-security" hidden>
|
|
151
|
+
<!-- Security content -->
|
|
152
|
+
</div>
|
|
153
|
+
<div role="tabpanel" id="panel-billing" aria-labelledby="tab-billing" hidden>
|
|
154
|
+
<!-- Billing content -->
|
|
155
|
+
</div>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Combobox / Autocomplete:**
|
|
159
|
+
```html
|
|
160
|
+
<label for="search-input">Search</label>
|
|
161
|
+
<div role="combobox" aria-expanded="true" aria-haspopup="listbox" aria-owns="search-results">
|
|
162
|
+
<input id="search-input" type="text" aria-autocomplete="list"
|
|
163
|
+
aria-controls="search-results" aria-activedescendant="result-2" />
|
|
164
|
+
</div>
|
|
165
|
+
<ul id="search-results" role="listbox">
|
|
166
|
+
<li id="result-1" role="option">React</li>
|
|
167
|
+
<li id="result-2" role="option" aria-selected="true">React Router</li>
|
|
168
|
+
<li id="result-3" role="option">React Query</li>
|
|
169
|
+
</ul>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Disclosure (expand/collapse):**
|
|
173
|
+
```html
|
|
174
|
+
<button aria-expanded="false" aria-controls="faq-answer-1">
|
|
175
|
+
What is your return policy?
|
|
176
|
+
</button>
|
|
177
|
+
<div id="faq-answer-1" hidden>
|
|
178
|
+
<p>You can return items within 30 days of purchase.</p>
|
|
179
|
+
</div>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### ARIA States Reference
|
|
183
|
+
|
|
184
|
+
| Attribute | Purpose | Values |
|
|
185
|
+
|-----------|---------|--------|
|
|
186
|
+
| `aria-expanded` | Collapsible sections, menus | `true` / `false` |
|
|
187
|
+
| `aria-selected` | Tabs, listbox options | `true` / `false` |
|
|
188
|
+
| `aria-checked` | Custom checkboxes, switches | `true` / `false` / `mixed` |
|
|
189
|
+
| `aria-pressed` | Toggle buttons | `true` / `false` |
|
|
190
|
+
| `aria-disabled` | Disabled controls (keeps focusable) | `true` / `false` |
|
|
191
|
+
| `aria-hidden` | Hide from assistive tech (still visible) | `true` / `false` |
|
|
192
|
+
| `aria-invalid` | Form validation errors | `true` / `false` / `grammar` / `spelling` |
|
|
193
|
+
| `aria-busy` | Content loading/updating | `true` / `false` |
|
|
194
|
+
| `aria-current` | Current item in a set | `page` / `step` / `location` / `date` / `true` |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Keyboard Navigation
|
|
199
|
+
|
|
200
|
+
### Tab Order
|
|
201
|
+
|
|
202
|
+
All interactive elements must be reachable via Tab in a logical order that matches visual layout.
|
|
203
|
+
|
|
204
|
+
```html
|
|
205
|
+
<!-- tabindex values -->
|
|
206
|
+
<!-- 0: follows natural DOM order (use this) -->
|
|
207
|
+
<button tabindex="0">Interactive element in DOM order</button>
|
|
208
|
+
|
|
209
|
+
<!-- -1: focusable via JS only, not in tab order -->
|
|
210
|
+
<div tabindex="-1" id="main-content">Focusable by script, not Tab</div>
|
|
211
|
+
|
|
212
|
+
<!-- positive: NEVER USE --- creates unpredictable tab order -->
|
|
213
|
+
<!-- <div tabindex="5">DO NOT DO THIS</div> -->
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Focus Management
|
|
217
|
+
|
|
218
|
+
**Modal dialog focus trap:**
|
|
219
|
+
```typescript
|
|
220
|
+
function trapFocus(modal: HTMLElement): () => void {
|
|
221
|
+
const focusableSelector = [
|
|
222
|
+
'a[href]', 'button:not([disabled])', 'input:not([disabled])',
|
|
223
|
+
'select:not([disabled])', 'textarea:not([disabled])',
|
|
224
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
225
|
+
].join(', ');
|
|
226
|
+
|
|
227
|
+
const focusableElements = modal.querySelectorAll<HTMLElement>(focusableSelector);
|
|
228
|
+
const firstElement = focusableElements[0];
|
|
229
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
230
|
+
|
|
231
|
+
// Save the element that opened the modal
|
|
232
|
+
const previouslyFocused = document.activeElement as HTMLElement;
|
|
233
|
+
|
|
234
|
+
function handleKeydown(event: KeyboardEvent): void {
|
|
235
|
+
if (event.key === 'Escape') {
|
|
236
|
+
closeModal();
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (event.key !== 'Tab') return;
|
|
241
|
+
|
|
242
|
+
if (event.shiftKey) {
|
|
243
|
+
if (document.activeElement === firstElement) {
|
|
244
|
+
event.preventDefault();
|
|
245
|
+
lastElement.focus();
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
if (document.activeElement === lastElement) {
|
|
249
|
+
event.preventDefault();
|
|
250
|
+
firstElement.focus();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
modal.addEventListener('keydown', handleKeydown);
|
|
256
|
+
firstElement.focus();
|
|
257
|
+
|
|
258
|
+
// Return cleanup function that restores focus
|
|
259
|
+
return () => {
|
|
260
|
+
modal.removeEventListener('keydown', handleKeydown);
|
|
261
|
+
previouslyFocused?.focus();
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Roving tabindex for composite widgets (tabs, toolbars, menus):**
|
|
267
|
+
```typescript
|
|
268
|
+
function rovingTabindex(container: HTMLElement, selector: string): void {
|
|
269
|
+
const items = Array.from(container.querySelectorAll<HTMLElement>(selector));
|
|
270
|
+
|
|
271
|
+
items.forEach((item, index) => {
|
|
272
|
+
item.setAttribute('tabindex', index === 0 ? '0' : '-1');
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
container.addEventListener('keydown', (event: KeyboardEvent) => {
|
|
276
|
+
const currentIndex = items.indexOf(event.target as HTMLElement);
|
|
277
|
+
if (currentIndex === -1) return;
|
|
278
|
+
|
|
279
|
+
let nextIndex: number;
|
|
280
|
+
|
|
281
|
+
switch (event.key) {
|
|
282
|
+
case 'ArrowRight':
|
|
283
|
+
case 'ArrowDown':
|
|
284
|
+
nextIndex = (currentIndex + 1) % items.length;
|
|
285
|
+
break;
|
|
286
|
+
case 'ArrowLeft':
|
|
287
|
+
case 'ArrowUp':
|
|
288
|
+
nextIndex = (currentIndex - 1 + items.length) % items.length;
|
|
289
|
+
break;
|
|
290
|
+
case 'Home':
|
|
291
|
+
nextIndex = 0;
|
|
292
|
+
break;
|
|
293
|
+
case 'End':
|
|
294
|
+
nextIndex = items.length - 1;
|
|
295
|
+
break;
|
|
296
|
+
default:
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
event.preventDefault();
|
|
301
|
+
items[currentIndex].setAttribute('tabindex', '-1');
|
|
302
|
+
items[nextIndex].setAttribute('tabindex', '0');
|
|
303
|
+
items[nextIndex].focus();
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Focus Indicators
|
|
309
|
+
|
|
310
|
+
```css
|
|
311
|
+
/* NEVER remove focus outlines globally */
|
|
312
|
+
/* *:focus { outline: none; } --- BANNED */
|
|
313
|
+
|
|
314
|
+
/* Use :focus-visible for keyboard-only focus styles */
|
|
315
|
+
:focus-visible {
|
|
316
|
+
outline: 2px solid var(--color-focus, #005fcc);
|
|
317
|
+
outline-offset: 2px;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/* Remove outline only for mouse clicks, keep for keyboard */
|
|
321
|
+
:focus:not(:focus-visible) {
|
|
322
|
+
outline: none;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* High-contrast focus for dark backgrounds */
|
|
326
|
+
.dark-section :focus-visible {
|
|
327
|
+
outline-color: #ffffff;
|
|
328
|
+
box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.3);
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Skip Links
|
|
333
|
+
|
|
334
|
+
```html
|
|
335
|
+
<body>
|
|
336
|
+
<a href="#main-content" class="skip-link">Skip to main content</a>
|
|
337
|
+
<a href="#search" class="skip-link">Skip to search</a>
|
|
338
|
+
<!-- header, nav... -->
|
|
339
|
+
<main id="main-content" tabindex="-1">...</main>
|
|
340
|
+
</body>
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
```css
|
|
344
|
+
.skip-link {
|
|
345
|
+
position: absolute;
|
|
346
|
+
top: -100%;
|
|
347
|
+
left: 16px;
|
|
348
|
+
padding: 8px 16px;
|
|
349
|
+
background: #000;
|
|
350
|
+
color: #fff;
|
|
351
|
+
font-weight: bold;
|
|
352
|
+
z-index: 10000;
|
|
353
|
+
text-decoration: none;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.skip-link:focus {
|
|
357
|
+
top: 8px;
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Screen Reader Patterns
|
|
364
|
+
|
|
365
|
+
### Live Regions
|
|
366
|
+
|
|
367
|
+
Use `aria-live` to announce dynamic content changes.
|
|
368
|
+
|
|
369
|
+
```html
|
|
370
|
+
<!-- Polite: announces after current speech finishes -->
|
|
371
|
+
<div aria-live="polite" aria-atomic="true" class="visually-hidden">
|
|
372
|
+
<!-- Inject status messages here via JS -->
|
|
373
|
+
</div>
|
|
374
|
+
|
|
375
|
+
<!-- Assertive: interrupts current speech (use sparingly) -->
|
|
376
|
+
<div role="alert" aria-live="assertive">
|
|
377
|
+
<!-- Critical error messages only -->
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<!-- Status: polite + role=status (for non-critical updates) -->
|
|
381
|
+
<div role="status" aria-live="polite">
|
|
382
|
+
3 results found
|
|
383
|
+
</div>
|
|
384
|
+
|
|
385
|
+
<!-- Log: polite, new entries appended (chat, activity feed) -->
|
|
386
|
+
<div role="log" aria-live="polite" aria-relevant="additions">
|
|
387
|
+
<!-- Chat messages appended here -->
|
|
388
|
+
</div>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Announcing dynamic changes:**
|
|
392
|
+
```typescript
|
|
393
|
+
function announce(message: string, priority: 'polite' | 'assertive' = 'polite'): void {
|
|
394
|
+
const announcer = document.getElementById(`${priority}-announcer`);
|
|
395
|
+
if (!announcer) return;
|
|
396
|
+
|
|
397
|
+
// Clear and re-set to force re-announcement
|
|
398
|
+
announcer.textContent = '';
|
|
399
|
+
requestAnimationFrame(() => {
|
|
400
|
+
announcer.textContent = message;
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Usage
|
|
405
|
+
announce('Item added to cart');
|
|
406
|
+
announce('Form submission failed. 2 errors found.', 'assertive');
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Visually Hidden Class
|
|
410
|
+
|
|
411
|
+
Content that must be read by screen readers but hidden visually.
|
|
412
|
+
|
|
413
|
+
```css
|
|
414
|
+
.visually-hidden {
|
|
415
|
+
position: absolute;
|
|
416
|
+
width: 1px;
|
|
417
|
+
height: 1px;
|
|
418
|
+
padding: 0;
|
|
419
|
+
margin: -1px;
|
|
420
|
+
overflow: hidden;
|
|
421
|
+
clip: rect(0, 0, 0, 0);
|
|
422
|
+
white-space: nowrap;
|
|
423
|
+
border: 0;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/* Allow the element to be focusable when navigated to */
|
|
427
|
+
.visually-hidden.focusable:focus {
|
|
428
|
+
position: static;
|
|
429
|
+
width: auto;
|
|
430
|
+
height: auto;
|
|
431
|
+
margin: 0;
|
|
432
|
+
overflow: visible;
|
|
433
|
+
clip: auto;
|
|
434
|
+
white-space: normal;
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Color Contrast
|
|
441
|
+
|
|
442
|
+
### Requirements
|
|
443
|
+
|
|
444
|
+
| Element | AA Minimum | AAA Enhanced |
|
|
445
|
+
|---------|------------|--------------|
|
|
446
|
+
| Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 |
|
|
447
|
+
| Large text (>= 18px / >= 14px bold) | 3:1 | 4.5:1 |
|
|
448
|
+
| UI components and graphical objects | 3:1 | 3:1 |
|
|
449
|
+
| Disabled controls | No requirement | No requirement |
|
|
450
|
+
| Logos and brand text | No requirement | No requirement |
|
|
451
|
+
|
|
452
|
+
### Never Rely on Color Alone
|
|
453
|
+
|
|
454
|
+
```html
|
|
455
|
+
<!-- WRONG: only color indicates error -->
|
|
456
|
+
<input style="border-color: red" />
|
|
457
|
+
|
|
458
|
+
<!-- CORRECT: color + icon + text + ARIA -->
|
|
459
|
+
<div class="field-group">
|
|
460
|
+
<label for="email">Email address</label>
|
|
461
|
+
<input id="email" type="email"
|
|
462
|
+
aria-invalid="true"
|
|
463
|
+
aria-describedby="email-error" />
|
|
464
|
+
<p id="email-error" class="error-message" role="alert">
|
|
465
|
+
<svg aria-hidden="true" class="error-icon"><!-- icon --></svg>
|
|
466
|
+
Please enter a valid email address (e.g., user@example.com)
|
|
467
|
+
</p>
|
|
468
|
+
</div>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Link Distinction
|
|
472
|
+
|
|
473
|
+
Links within body text must be distinguishable from surrounding text by more than color alone (underline, bold, icon, or 3:1 contrast difference from surrounding text).
|
|
474
|
+
|
|
475
|
+
```css
|
|
476
|
+
/* Links in body text must have underline OR 3:1 contrast difference from surrounding text */
|
|
477
|
+
p a, li a, td a {
|
|
478
|
+
text-decoration: underline;
|
|
479
|
+
text-underline-offset: 2px;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* Navigation links where context makes role obvious can omit underline */
|
|
483
|
+
nav a {
|
|
484
|
+
text-decoration: none;
|
|
485
|
+
}
|
|
486
|
+
nav a:hover,
|
|
487
|
+
nav a:focus-visible {
|
|
488
|
+
text-decoration: underline;
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## Reduced Motion
|
|
495
|
+
|
|
496
|
+
```css
|
|
497
|
+
/* Respect user preference */
|
|
498
|
+
@media (prefers-reduced-motion: reduce) {
|
|
499
|
+
*,
|
|
500
|
+
*::before,
|
|
501
|
+
*::after {
|
|
502
|
+
animation-duration: 0.01ms !important;
|
|
503
|
+
animation-iteration-count: 1 !important;
|
|
504
|
+
transition-duration: 0.01ms !important;
|
|
505
|
+
scroll-behavior: auto !important;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/* Provide alternatives, not just removal */
|
|
510
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
511
|
+
.hero-animation {
|
|
512
|
+
animation: slide-in 0.5s ease-out;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/* Always safe: opacity transitions are fine for reduced motion users */
|
|
517
|
+
.fade-in {
|
|
518
|
+
opacity: 0;
|
|
519
|
+
transition: opacity 0.2s ease-in;
|
|
520
|
+
}
|
|
521
|
+
.fade-in.visible {
|
|
522
|
+
opacity: 1;
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
**In JavaScript:**
|
|
527
|
+
```typescript
|
|
528
|
+
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
529
|
+
|
|
530
|
+
function animateElement(element: HTMLElement): void {
|
|
531
|
+
if (prefersReducedMotion) {
|
|
532
|
+
element.style.opacity = '1'; // Instant, no animation
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
element.animate(
|
|
536
|
+
[{ opacity: 0, transform: 'translateY(20px)' }, { opacity: 1, transform: 'translateY(0)' }],
|
|
537
|
+
{ duration: 300, easing: 'ease-out' }
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## Form Accessibility
|
|
545
|
+
|
|
546
|
+
### Labels
|
|
547
|
+
|
|
548
|
+
Every form control must have a programmatically associated label.
|
|
549
|
+
|
|
550
|
+
```html
|
|
551
|
+
<!-- Explicit label (preferred) -->
|
|
552
|
+
<label for="username">Username</label>
|
|
553
|
+
<input id="username" type="text" name="username" required />
|
|
554
|
+
|
|
555
|
+
<!-- Implicit label -->
|
|
556
|
+
<label>
|
|
557
|
+
Username
|
|
558
|
+
<input type="text" name="username" required />
|
|
559
|
+
</label>
|
|
560
|
+
|
|
561
|
+
<!-- NEVER use placeholder as the only label -->
|
|
562
|
+
<!-- WRONG -->
|
|
563
|
+
<input type="email" placeholder="Email" />
|
|
564
|
+
|
|
565
|
+
<!-- CORRECT: label + optional placeholder -->
|
|
566
|
+
<label for="email">Email address</label>
|
|
567
|
+
<input id="email" type="email" placeholder="user@example.com" />
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Error Messages
|
|
571
|
+
|
|
572
|
+
```html
|
|
573
|
+
<form novalidate>
|
|
574
|
+
<!-- Error summary at top of form -->
|
|
575
|
+
<div id="error-summary" role="alert" aria-live="assertive" tabindex="-1">
|
|
576
|
+
<h2>There are 2 errors in this form</h2>
|
|
577
|
+
<ul>
|
|
578
|
+
<li><a href="#email">Email address is required</a></li>
|
|
579
|
+
<li><a href="#password">Password must be at least 8 characters</a></li>
|
|
580
|
+
</ul>
|
|
581
|
+
</div>
|
|
582
|
+
|
|
583
|
+
<!-- Individual field with error -->
|
|
584
|
+
<div class="field-group">
|
|
585
|
+
<label for="email">
|
|
586
|
+
Email address
|
|
587
|
+
<span aria-hidden="true">*</span>
|
|
588
|
+
<span class="visually-hidden">(required)</span>
|
|
589
|
+
</label>
|
|
590
|
+
<input id="email" type="email" name="email"
|
|
591
|
+
required
|
|
592
|
+
aria-required="true"
|
|
593
|
+
aria-invalid="true"
|
|
594
|
+
aria-describedby="email-error email-hint" />
|
|
595
|
+
<p id="email-hint" class="hint">We will never share your email.</p>
|
|
596
|
+
<p id="email-error" class="error-message">Email address is required</p>
|
|
597
|
+
</div>
|
|
598
|
+
</form>
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Required Fields
|
|
602
|
+
|
|
603
|
+
```html
|
|
604
|
+
<!-- Indicate required at the form level -->
|
|
605
|
+
<p>Fields marked with <span aria-hidden="true">*</span>
|
|
606
|
+
<span class="visually-hidden">asterisk</span> are required.</p>
|
|
607
|
+
|
|
608
|
+
<!-- On the field -->
|
|
609
|
+
<label for="name">
|
|
610
|
+
Full name <span aria-hidden="true">*</span>
|
|
611
|
+
</label>
|
|
612
|
+
<input id="name" type="text" required aria-required="true" />
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
617
|
+
## Table Accessibility
|
|
618
|
+
|
|
619
|
+
### Data Tables
|
|
620
|
+
|
|
621
|
+
```html
|
|
622
|
+
<table>
|
|
623
|
+
<caption>Q3 2025 Sales by Region</caption>
|
|
624
|
+
<thead>
|
|
625
|
+
<tr>
|
|
626
|
+
<th scope="col">Region</th>
|
|
627
|
+
<th scope="col">Revenue</th>
|
|
628
|
+
<th scope="col">Growth</th>
|
|
629
|
+
</tr>
|
|
630
|
+
</thead>
|
|
631
|
+
<tbody>
|
|
632
|
+
<tr>
|
|
633
|
+
<th scope="row">North America</th>
|
|
634
|
+
<td>$1.2M</td>
|
|
635
|
+
<td>+15%</td>
|
|
636
|
+
</tr>
|
|
637
|
+
<tr>
|
|
638
|
+
<th scope="row">Europe</th>
|
|
639
|
+
<td>$800K</td>
|
|
640
|
+
<td>+8%</td>
|
|
641
|
+
</tr>
|
|
642
|
+
</tbody>
|
|
643
|
+
</table>
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### Complex Tables
|
|
647
|
+
|
|
648
|
+
```html
|
|
649
|
+
<table>
|
|
650
|
+
<caption>Employee Schedule</caption>
|
|
651
|
+
<thead>
|
|
652
|
+
<tr>
|
|
653
|
+
<td></td>
|
|
654
|
+
<th scope="col" id="mon">Monday</th>
|
|
655
|
+
<th scope="col" id="tue">Tuesday</th>
|
|
656
|
+
</tr>
|
|
657
|
+
</thead>
|
|
658
|
+
<tbody>
|
|
659
|
+
<tr>
|
|
660
|
+
<th scope="row" id="morning">Morning</th>
|
|
661
|
+
<td headers="mon morning">Alice</td>
|
|
662
|
+
<td headers="tue morning">Bob</td>
|
|
663
|
+
</tr>
|
|
664
|
+
</tbody>
|
|
665
|
+
</table>
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
### Layout Tables (Avoid)
|
|
669
|
+
|
|
670
|
+
If you must use a table for layout (you should not), add `role="presentation"` to remove table semantics from the accessibility tree.
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
## Image Alternatives
|
|
675
|
+
|
|
676
|
+
```html
|
|
677
|
+
<!-- Informative image: describe the content -->
|
|
678
|
+
<img src="chart.png" alt="Bar chart showing 40% increase in Q3 sales compared to Q2" />
|
|
679
|
+
|
|
680
|
+
<!-- Decorative image: empty alt -->
|
|
681
|
+
<img src="decorative-swirl.png" alt="" role="presentation" />
|
|
682
|
+
|
|
683
|
+
<!-- Functional image (inside a link/button): describe the action -->
|
|
684
|
+
<a href="/home">
|
|
685
|
+
<img src="logo.svg" alt="Acme Corp - Go to homepage" />
|
|
686
|
+
</a>
|
|
687
|
+
|
|
688
|
+
<!-- Complex image with long description -->
|
|
689
|
+
<figure>
|
|
690
|
+
<img src="infographic.png" alt="2025 industry trends infographic"
|
|
691
|
+
aria-describedby="infographic-desc" />
|
|
692
|
+
<figcaption id="infographic-desc">
|
|
693
|
+
The infographic shows five key trends: AI adoption increased 45%,
|
|
694
|
+
remote work stabilized at 35%, cloud spending grew 22%...
|
|
695
|
+
</figcaption>
|
|
696
|
+
</figure>
|
|
697
|
+
|
|
698
|
+
<!-- Icon buttons -->
|
|
699
|
+
<button aria-label="Close dialog">
|
|
700
|
+
<svg aria-hidden="true" focusable="false"><!-- X icon --></svg>
|
|
701
|
+
</button>
|
|
702
|
+
|
|
703
|
+
<!-- SVG with title -->
|
|
704
|
+
<svg role="img" aria-labelledby="svg-title">
|
|
705
|
+
<title id="svg-title">Warning: connection unstable</title>
|
|
706
|
+
<!-- SVG paths -->
|
|
707
|
+
</svg>
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## Testing Tools and Methods
|
|
713
|
+
|
|
714
|
+
### Automated Testing
|
|
715
|
+
|
|
716
|
+
| Tool | What It Catches | Integration |
|
|
717
|
+
|------|----------------|-------------|
|
|
718
|
+
| **axe-core** | ~57% of WCAG issues | Jest, Playwright, CI/CD |
|
|
719
|
+
| **Lighthouse** | Performance + a11y audit | Chrome DevTools, CLI |
|
|
720
|
+
| **eslint-plugin-jsx-a11y** | JSX-specific issues | ESLint config |
|
|
721
|
+
| **pa11y** | WCAG conformance | CLI, CI/CD |
|
|
722
|
+
| **Storybook a11y addon** | Component-level issues | Storybook |
|
|
723
|
+
|
|
724
|
+
**axe with Playwright:**
|
|
725
|
+
```typescript
|
|
726
|
+
import { test, expect } from '@playwright/test';
|
|
727
|
+
import AxeBuilder from '@axe-core/playwright';
|
|
728
|
+
|
|
729
|
+
test('page has no accessibility violations', async ({ page }) => {
|
|
730
|
+
await page.goto('/dashboard');
|
|
731
|
+
const results = await new AxeBuilder({ page })
|
|
732
|
+
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
|
|
733
|
+
.analyze();
|
|
734
|
+
|
|
735
|
+
expect(results.violations).toEqual([]);
|
|
736
|
+
});
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
**axe with Vitest and Testing Library:**
|
|
740
|
+
```typescript
|
|
741
|
+
import { render } from '@testing-library/react';
|
|
742
|
+
import { axe, toHaveNoViolations } from 'jest-axe';
|
|
743
|
+
|
|
744
|
+
expect.extend(toHaveNoViolations);
|
|
745
|
+
|
|
746
|
+
test('form is accessible', async () => {
|
|
747
|
+
const { container } = render(<LoginForm />);
|
|
748
|
+
const results = await axe(container);
|
|
749
|
+
expect(results).toHaveNoViolations();
|
|
750
|
+
});
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### Manual Testing Checklist
|
|
754
|
+
|
|
755
|
+
- [ ] **Keyboard only:** Complete all tasks using only keyboard (Tab, Enter, Space, Escape, Arrows)
|
|
756
|
+
- [ ] **Screen reader:** Test with NVDA (Windows), VoiceOver (macOS/iOS), TalkBack (Android)
|
|
757
|
+
- [ ] **Zoom 200%:** All content remains usable at 200% browser zoom
|
|
758
|
+
- [ ] **Zoom 400%:** Content reflows without horizontal scroll (WCAG 2.1 1.4.10)
|
|
759
|
+
- [ ] **High contrast:** Test with Windows High Contrast Mode and forced-colors
|
|
760
|
+
- [ ] **Reduced motion:** Test with prefers-reduced-motion: reduce
|
|
761
|
+
- [ ] **No images:** Verify alt text conveys meaning when images fail to load
|
|
762
|
+
- [ ] **Focus order:** Tab order matches visual/logical order
|
|
763
|
+
- [ ] **Error recovery:** Users can identify and correct all form errors
|
|
764
|
+
|
|
765
|
+
### Screen Reader Commands
|
|
766
|
+
|
|
767
|
+
| Action | VoiceOver (macOS) | NVDA (Windows) |
|
|
768
|
+
|--------|-------------------|----------------|
|
|
769
|
+
| Start/Stop | Cmd + F5 | Ctrl + Alt + N |
|
|
770
|
+
| Next item | VO + Right | Down Arrow |
|
|
771
|
+
| Previous item | VO + Left | Up Arrow |
|
|
772
|
+
| Activate | VO + Space | Enter |
|
|
773
|
+
| Headings list | VO + U, arrows | H / Shift + H |
|
|
774
|
+
| Landmarks | VO + U, arrows | D / Shift + D |
|
|
775
|
+
| Forms mode | Auto | Enter on form field |
|
|
776
|
+
|
|
777
|
+
---
|
|
778
|
+
|
|
779
|
+
## Legal Requirements
|
|
780
|
+
|
|
781
|
+
| Standard | Jurisdiction | Level | Applies To |
|
|
782
|
+
|----------|-------------|-------|------------|
|
|
783
|
+
| **ADA Title III** | United States | WCAG 2.1 AA (DOJ guidance) | Public accommodations (most commercial websites) |
|
|
784
|
+
| **Section 508** | United States | WCAG 2.0 AA | Federal agencies and contractors |
|
|
785
|
+
| **EAA (European Accessibility Act)** | European Union | EN 301 549 / WCAG 2.1 AA | Products and services sold in the EU (June 2025) |
|
|
786
|
+
| **AODA** | Ontario, Canada | WCAG 2.0 AA | Organizations with 50+ employees |
|
|
787
|
+
| **DDA** | United Kingdom | WCAG 2.1 AA | Public sector and large organizations |
|
|
788
|
+
|
|
789
|
+
---
|
|
790
|
+
|
|
791
|
+
## Common Anti-Patterns
|
|
792
|
+
|
|
793
|
+
| Anti-Pattern | Why It Is Wrong | Correct Approach |
|
|
794
|
+
|-------------|-----------------|------------------|
|
|
795
|
+
| Div/span soup with click handlers | Not focusable, no role, no keyboard support | Use `<button>` or `<a href>` |
|
|
796
|
+
| `aria-label` on non-interactive `<div>` | Screen readers may ignore or misrepresent | Use heading, visually-hidden text, or landmark role |
|
|
797
|
+
| Placeholder as sole label | Disappears on input, low contrast, not announced consistently | Use `<label>` element |
|
|
798
|
+
| `tabindex="5"` (positive values) | Creates unpredictable tab order | Use `tabindex="0"` and DOM order |
|
|
799
|
+
| `role="button"` without keyboard handler | Looks like a button but Enter/Space does nothing | Use native `<button>` or add keydown handler |
|
|
800
|
+
| `aria-hidden="true"` on focusable element | Creates ghost focus (focused but invisible to AT) | Remove from tab order too: `tabindex="-1"` |
|
|
801
|
+
| Auto-playing video/audio | Disorienting, interferes with screen readers | Require user-initiated playback |
|
|
802
|
+
| Custom `<select>` without listbox role | Broken for keyboard and screen reader users | Use native `<select>` or full ARIA listbox pattern |
|
|
803
|
+
| `outline: none` globally | Removes keyboard focus indicator for all users | Use `:focus-visible` for keyboard-only styles |
|
|
804
|
+
| `title` attribute for tooltips | Inconsistent AT support, not keyboard accessible | Use `aria-describedby` pointing to visible text |
|
|
805
|
+
| Infinite scroll without alternatives | Keyboard users cannot reach footer, disorienting | Provide "Load more" button or pagination |
|
|
806
|
+
| Low-contrast disabled buttons | Users cannot tell what is disabled | Ensure 3:1 contrast or add text indicator |
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
|
|
810
|
+
## Accessibility Decision Tree
|
|
811
|
+
|
|
812
|
+
```
|
|
813
|
+
Is there a native HTML element for this?
|
|
814
|
+
YES --> Use it. Done.
|
|
815
|
+
NO --> Does this widget exist in WAI-ARIA Authoring Practices?
|
|
816
|
+
YES --> Follow that pattern exactly (roles, states, keyboard)
|
|
817
|
+
NO --> Simplify the design. Complex custom widgets are a11y debt.
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
## References
|
|
821
|
+
|
|
822
|
+
- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)
|
|
823
|
+
- [WCAG 2.2 What's New](https://www.w3.org/TR/WCAG22/)
|
|
824
|
+
- [WAI-ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/)
|
|
825
|
+
- [Deque axe Rules](https://dequeuniversity.com/rules/axe/)
|
|
826
|
+
- [Inclusive Components](https://inclusive-components.design/)
|
|
827
|
+
- [A11y Project Checklist](https://www.a11yproject.com/checklist/)
|