@verndale/accessibility-standards 1.0.0 → 3.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.
Files changed (171) hide show
  1. package/OPERATING.md +3 -1
  2. package/README.md +4 -0
  3. package/bin/accessibility-standards.mjs +1 -1
  4. package/dist/manifest.json +159 -101
  5. package/dist/profiles/ai-orchestration/coverage-manifest.json +724 -68
  6. package/dist/profiles/ai-orchestration/implementation/accessibility.md +825 -10
  7. package/dist/profiles/ai-orchestration/pattern-contracts.json +1015 -343
  8. package/dist/profiles/ai-orchestration/patterns/accordion.md +14 -0
  9. package/dist/profiles/ai-orchestration/patterns/alert.md +14 -0
  10. package/dist/profiles/ai-orchestration/patterns/carousel.md +14 -0
  11. package/dist/profiles/ai-orchestration/patterns/checkbox.md +27 -0
  12. package/dist/profiles/ai-orchestration/patterns/combobox.md +14 -0
  13. package/dist/profiles/ai-orchestration/patterns/consequential-submission.md +15 -1
  14. package/dist/profiles/ai-orchestration/patterns/dialog.md +14 -0
  15. package/dist/profiles/ai-orchestration/patterns/disclosure.md +14 -0
  16. package/dist/profiles/ai-orchestration/patterns/dynamic-status.md +14 -0
  17. package/dist/profiles/ai-orchestration/patterns/field.md +15 -0
  18. package/dist/profiles/ai-orchestration/patterns/image.md +14 -0
  19. package/dist/profiles/ai-orchestration/patterns/listbox.md +14 -0
  20. package/dist/profiles/ai-orchestration/patterns/media-player.md +17 -0
  21. package/dist/profiles/ai-orchestration/patterns/menu-button.md +14 -0
  22. package/dist/profiles/ai-orchestration/patterns/menu.md +30 -0
  23. package/dist/profiles/ai-orchestration/patterns/pagination.md +14 -0
  24. package/dist/profiles/ai-orchestration/patterns/popover.md +15 -0
  25. package/dist/profiles/ai-orchestration/patterns/progress.md +15 -0
  26. package/dist/profiles/ai-orchestration/patterns/radio-group.md +27 -0
  27. package/dist/profiles/ai-orchestration/patterns/slider.md +31 -0
  28. package/dist/profiles/ai-orchestration/patterns/spinbutton.md +28 -0
  29. package/dist/profiles/ai-orchestration/patterns/tabs.md +14 -0
  30. package/dist/profiles/ai-orchestration/patterns/tooltip.md +14 -0
  31. package/dist/profiles/ai-orchestration/patterns/tree-view.md +31 -0
  32. package/dist/profiles/ai-orchestration/patterns/validation.md +15 -0
  33. package/dist/profiles/ai-orchestration/review/accessibility.md +21 -6
  34. package/dist/profiles/ai-orchestration/semantics/accessible-authentication.md +13 -0
  35. package/dist/profiles/ai-orchestration/semantics/accessible-name.md +8 -1
  36. package/dist/profiles/ai-orchestration/semantics/alert.md +7 -0
  37. package/dist/profiles/ai-orchestration/semantics/consequential-action.md +6 -1
  38. package/dist/profiles/ai-orchestration/semantics/consistent-help.md +13 -0
  39. package/dist/profiles/ai-orchestration/semantics/data-table.md +7 -1
  40. package/dist/profiles/ai-orchestration/semantics/dragging-alternative.md +13 -0
  41. package/dist/profiles/ai-orchestration/semantics/expanded-state.md +6 -0
  42. package/dist/profiles/ai-orchestration/semantics/focus.initial.md +4 -0
  43. package/dist/profiles/ai-orchestration/semantics/focus.return.md +4 -0
  44. package/dist/profiles/ai-orchestration/semantics/focus.visible.md +8 -1
  45. package/dist/profiles/ai-orchestration/semantics/form-error.md +8 -1
  46. package/dist/profiles/ai-orchestration/semantics/form-label.md +7 -0
  47. package/dist/profiles/ai-orchestration/semantics/form-required.md +7 -0
  48. package/dist/profiles/ai-orchestration/semantics/headings.md +7 -0
  49. package/dist/profiles/ai-orchestration/semantics/keyboard.escape.md +4 -0
  50. package/dist/profiles/ai-orchestration/semantics/keyboard.md +7 -0
  51. package/dist/profiles/ai-orchestration/semantics/landmarks.md +6 -0
  52. package/dist/profiles/ai-orchestration/semantics/live-status.md +7 -1
  53. package/dist/profiles/ai-orchestration/semantics/media-alternatives.md +11 -0
  54. package/dist/profiles/ai-orchestration/semantics/motion-control.md +8 -1
  55. package/dist/profiles/ai-orchestration/semantics/name-role-value.md +6 -1
  56. package/dist/profiles/ai-orchestration/semantics/native-dialog.md +7 -0
  57. package/dist/profiles/ai-orchestration/semantics/native-elements.md +5 -0
  58. package/dist/profiles/ai-orchestration/semantics/non-text-alternative.md +5 -0
  59. package/dist/profiles/ai-orchestration/semantics/redundant-entry.md +13 -0
  60. package/dist/profiles/ai-orchestration/semantics/roles-states-properties.md +6 -0
  61. package/dist/profiles/ai-orchestration/semantics/selected-state.md +6 -0
  62. package/dist/profiles/ai-orchestration/semantics/target-size.md +6 -1
  63. package/dist/profiles/ai-orchestration/semantics.json +843 -100
  64. package/dist/profiles/ai-orchestration/testing/accessibility.md +33 -3
  65. package/dist/profiles/ai-orchestration/ui-design-brain-bindings.json +836 -0
  66. package/dist/profiles/conductor/a11y-semantics.md +270 -10
  67. package/dist/profiles/conductor/accessibility-quality.md +557 -1
  68. package/dist/profiles/conductor/applicability-matrix.json +270 -230
  69. package/dist/profiles/conductor/coverage-manifest.json +724 -68
  70. package/dist/profiles/conductor/pattern-contracts.json +1015 -343
  71. package/dist/profiles/conductor/patterns/accordion.json +42 -24
  72. package/dist/profiles/conductor/patterns/alert.json +36 -18
  73. package/dist/profiles/conductor/patterns/carousel.json +43 -25
  74. package/dist/profiles/conductor/patterns/checkbox.json +67 -0
  75. package/dist/profiles/conductor/patterns/combobox.json +44 -26
  76. package/dist/profiles/conductor/patterns/consequential-submission.json +41 -22
  77. package/dist/profiles/conductor/patterns/dialog.json +44 -26
  78. package/dist/profiles/conductor/patterns/disclosure.json +40 -22
  79. package/dist/profiles/conductor/patterns/dynamic-status.json +38 -19
  80. package/dist/profiles/conductor/patterns/field.json +58 -22
  81. package/dist/profiles/conductor/patterns/image.json +48 -19
  82. package/dist/profiles/conductor/patterns/listbox.json +42 -24
  83. package/dist/profiles/conductor/patterns/media-player.json +76 -26
  84. package/dist/profiles/conductor/patterns/menu-button.json +41 -23
  85. package/dist/profiles/conductor/patterns/menu.json +78 -0
  86. package/dist/profiles/conductor/patterns/pagination.json +41 -22
  87. package/dist/profiles/conductor/patterns/popover.json +49 -23
  88. package/dist/profiles/conductor/patterns/progress.json +45 -20
  89. package/dist/profiles/conductor/patterns/radio-group.json +69 -0
  90. package/dist/profiles/conductor/patterns/slider.json +84 -0
  91. package/dist/profiles/conductor/patterns/spinbutton.json +74 -0
  92. package/dist/profiles/conductor/patterns/tabs.json +41 -23
  93. package/dist/profiles/conductor/patterns/tooltip.json +38 -20
  94. package/dist/profiles/conductor/patterns/tree-view.json +77 -0
  95. package/dist/profiles/conductor/patterns/validation.json +59 -23
  96. package/dist/profiles/conductor/semantics.json +843 -100
  97. package/dist/profiles/conductor/ui-design-brain-bindings.json +836 -0
  98. package/dist/projection-manifest.json +123 -82
  99. package/dist/requirements-to-implementation.md +8 -0
  100. package/lib/build-manifest.mjs +12 -6
  101. package/lib/build.mjs +21 -7
  102. package/lib/compile-applicability.mjs +131 -10
  103. package/lib/coverage.mjs +20 -0
  104. package/lib/digest.mjs +8 -0
  105. package/lib/index.mjs +1 -1
  106. package/lib/load.mjs +44 -1
  107. package/lib/provenance.mjs +51 -0
  108. package/lib/render.mjs +115 -31
  109. package/lib/sync.mjs +242 -28
  110. package/lib/validate.mjs +557 -24
  111. package/package.json +27 -10
  112. package/profiles/ai-orchestration/profile.json +1 -1
  113. package/profiles/ai-orchestration/templates/patterns/README.md +1 -1
  114. package/profiles/ai-orchestration/templates/review/README.md +1 -1
  115. package/profiles/ai-orchestration/templates/semantics/README.md +1 -1
  116. package/profiles/ai-orchestration/templates/testing/README.md +1 -1
  117. package/profiles/conductor/profile.json +1 -1
  118. package/profiles/conductor/templates/evidence/README.md +1 -1
  119. package/profiles/conductor/templates/patterns/README.md +1 -1
  120. package/profiles/conductor/templates/semantics/README.md +1 -1
  121. package/schemas/consumer-config.schema.json +1 -1
  122. package/schemas/contract.schema.json +1 -0
  123. package/schemas/manifest.schema.json +1 -1
  124. package/schemas/pattern.schema.json +98 -1
  125. package/schemas/profile.schema.json +1 -1
  126. package/schemas/projection-manifest.schema.json +84 -1
  127. package/schemas/semantic.schema.json +26 -1
  128. package/schemas/standards-reference.schema.json +105 -0
  129. package/schemas/ui-design-brain-bindings.schema.json +86 -0
  130. package/schemas/wcag-coverage.schema.json +93 -0
  131. package/src/applicability/facts.yml +27 -1
  132. package/src/applicability/matrix.yml +8 -9
  133. package/src/applicability/ui-design-brain-bindings.yml +196 -0
  134. package/src/contract.yml +1 -0
  135. package/src/coverage/wcag-2.2.yml +68 -0
  136. package/src/patterns/disclosure/accordion.yml +1 -1
  137. package/src/patterns/disclosure/disclosure.yml +1 -1
  138. package/src/patterns/feedback/alert.yml +1 -1
  139. package/src/patterns/feedback/dynamic-status.yml +1 -1
  140. package/src/patterns/feedback/progress.yml +1 -1
  141. package/src/patterns/forms/consequential-submission.yml +1 -1
  142. package/src/patterns/forms/field.yml +1 -1
  143. package/src/patterns/forms/spinbutton.yml +1 -0
  144. package/src/patterns/forms/validation.yml +1 -1
  145. package/src/patterns/media/carousel.yml +1 -1
  146. package/src/patterns/media/image.yml +1 -1
  147. package/src/patterns/media/media-player.yml +1 -1
  148. package/src/patterns/navigation/menu-button.yml +1 -1
  149. package/src/patterns/navigation/menu.yml +1 -0
  150. package/src/patterns/navigation/pagination.yml +1 -1
  151. package/src/patterns/navigation/tabs.yml +1 -1
  152. package/src/patterns/navigation/tree-view.yml +1 -0
  153. package/src/patterns/overlays/dialog.yml +1 -1
  154. package/src/patterns/overlays/popover.yml +1 -1
  155. package/src/patterns/overlays/tooltip.yml +1 -1
  156. package/src/patterns/selection/checkbox.yml +1 -0
  157. package/src/patterns/selection/combobox.yml +1 -1
  158. package/src/patterns/selection/listbox.yml +1 -1
  159. package/src/patterns/selection/radio-group.yml +1 -0
  160. package/src/patterns/selection/slider.yml +1 -0
  161. package/src/semantics/accessible-names.yml +1 -1
  162. package/src/semantics/forms.yml +1 -1
  163. package/src/semantics/headings-landmarks.yml +1 -1
  164. package/src/semantics/keyboard-focus.yml +1 -1
  165. package/src/semantics/live-regions.yml +1 -1
  166. package/src/semantics/media.yml +1 -1
  167. package/src/semantics/native-elements.yml +1 -1
  168. package/src/semantics/roles-states-properties.yml +1 -1
  169. package/src/semantics/tables.yml +1 -1
  170. package/src/semantics/wcag-2.2.yml +1 -0
  171. package/src/sources.yml +1 -1
@@ -1,217 +1,321 @@
1
1
  {
2
2
  "_generated": "GENERATED by @verndale/accessibility-standards; DO NOT EDIT",
3
- "schema_version": 1,
3
+ "_provenance": {
4
+ "package": "@verndale/accessibility-standards@3.0.0",
5
+ "profile": "ai-orchestration",
6
+ "profile_digest": "de396e9a23010dff2e8abf3ae7e8500153599583ffa31a595b3a94fbe9df3da4",
7
+ "profile_version": "3.0.0",
8
+ "schema_version": 3,
9
+ "source_digest": "708ac82783bfb5ebcce31e4dada15d8580863f5e37b32d1807adf61e415ed5af"
10
+ },
4
11
  "patterns": [
5
12
  {
6
- "id": "pattern.accordion",
7
- "version": "1.0.0",
8
- "title": "Accordion",
9
- "kind": "pattern",
10
- "requires": [
11
- "semantics.native-elements",
12
- "semantics.accessible-name",
13
- "semantics.expanded-state",
14
- "semantics.keyboard",
15
- "semantics.focus.visible"
16
- ],
17
13
  "activation": {
18
- "fact": "component.pattern",
19
- "equals": "accordion"
14
+ "contains": {
15
+ "fact": "component.accessibility_pattern_ids",
16
+ "value": "pattern.accordion"
17
+ }
20
18
  },
21
- "scope": "Grouped disclosure sections",
22
19
  "behavior": [
23
20
  "Toggle only the controlled panel",
24
21
  "Preserve DOM and focus order"
25
22
  ],
26
- "product_decisions": [
27
- "single_or_multiple_open"
23
+ "evidence_routes": [
24
+ "unit",
25
+ "axe",
26
+ "e2e",
27
+ "human"
28
28
  ],
29
29
  "functional_spec_bindings": [
30
30
  "behavior",
31
31
  "states",
32
32
  "keyboard"
33
33
  ],
34
+ "id": "pattern.accordion",
34
35
  "implementation_outcomes": [
35
36
  "accordion-control",
36
37
  "accordion-panel"
37
38
  ],
38
- "evidence_routes": [
39
- "unit",
40
- "axe",
41
- "e2e",
42
- "human"
43
- ]
44
- },
45
- {
46
- "id": "pattern.alert",
47
- "version": "1.0.0",
48
- "title": "Alert",
49
39
  "kind": "pattern",
40
+ "product_decisions": [
41
+ "single_or_multiple_open"
42
+ ],
50
43
  "requires": [
51
- "semantics.alert"
44
+ "semantics.native-elements",
45
+ "semantics.accessible-name",
46
+ "semantics.expanded-state",
47
+ "semantics.keyboard",
48
+ "semantics.focus.visible"
49
+ ],
50
+ "scope": "Grouped disclosure sections",
51
+ "standards_refs": [
52
+ {
53
+ "authority": "aria-apg",
54
+ "identifier": "accordion",
55
+ "normative": false,
56
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/accordion/"
57
+ }
52
58
  ],
59
+ "title": "Accordion",
60
+ "version": "1.0.0"
61
+ },
62
+ {
53
63
  "activation": {
54
- "fact": "component.pattern",
55
- "equals": "alert"
64
+ "contains": {
65
+ "fact": "component.accessibility_pattern_ids",
66
+ "value": "pattern.alert"
67
+ }
56
68
  },
57
- "scope": "Urgent message",
58
69
  "behavior": [
59
70
  "Announce once without moving focus"
60
71
  ],
61
- "product_decisions": [
62
- "urgency"
72
+ "evidence_routes": [
73
+ "unit",
74
+ "human"
63
75
  ],
64
76
  "functional_spec_bindings": [
65
77
  "messaging"
66
78
  ],
79
+ "id": "pattern.alert",
67
80
  "implementation_outcomes": [
68
81
  "alert-announcement"
69
82
  ],
70
- "evidence_routes": [
71
- "unit",
72
- "human"
73
- ]
74
- },
75
- {
76
- "id": "pattern.carousel",
77
- "version": "1.0.0",
78
- "title": "Carousel",
79
83
  "kind": "pattern",
84
+ "product_decisions": [
85
+ "urgency"
86
+ ],
80
87
  "requires": [
81
- "semantics.accessible-name",
82
- "semantics.keyboard",
83
- "semantics.focus.visible",
84
- "semantics.motion-control",
85
- "semantics.live-status"
88
+ "semantics.alert"
89
+ ],
90
+ "scope": "Urgent message",
91
+ "standards_refs": [
92
+ {
93
+ "authority": "aria-apg",
94
+ "identifier": "alert",
95
+ "normative": false,
96
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/alert/"
97
+ }
86
98
  ],
99
+ "title": "Alert",
100
+ "version": "1.0.0"
101
+ },
102
+ {
87
103
  "activation": {
88
- "fact": "component.pattern",
89
- "equals": "carousel"
104
+ "contains": {
105
+ "fact": "component.accessibility_pattern_ids",
106
+ "value": "pattern.carousel"
107
+ }
90
108
  },
91
- "scope": "Rotating content set",
92
109
  "behavior": [
93
110
  "Pause rotation on interaction",
94
111
  "Provide named controls and current position"
95
112
  ],
96
- "product_decisions": [
97
- "auto_rotation",
98
- "looping"
113
+ "evidence_routes": [
114
+ "unit",
115
+ "axe",
116
+ "e2e",
117
+ "human"
99
118
  ],
100
119
  "functional_spec_bindings": [
101
120
  "behavior",
102
121
  "states",
103
122
  "controls"
104
123
  ],
124
+ "id": "pattern.carousel",
105
125
  "implementation_outcomes": [
106
126
  "carousel-controls",
107
127
  "carousel-rotation"
108
128
  ],
129
+ "kind": "pattern",
130
+ "product_decisions": [
131
+ "auto_rotation",
132
+ "looping"
133
+ ],
134
+ "requires": [
135
+ "semantics.accessible-name",
136
+ "semantics.keyboard",
137
+ "semantics.focus.visible",
138
+ "semantics.motion-control",
139
+ "semantics.live-status"
140
+ ],
141
+ "scope": "Rotating content set",
142
+ "standards_refs": [
143
+ {
144
+ "authority": "aria-apg",
145
+ "identifier": "carousel",
146
+ "normative": false,
147
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/carousel/"
148
+ }
149
+ ],
150
+ "title": "Carousel",
151
+ "version": "1.0.0"
152
+ },
153
+ {
154
+ "activation": {
155
+ "contains": {
156
+ "fact": "component.accessibility_pattern_ids",
157
+ "value": "pattern.checkbox"
158
+ }
159
+ },
160
+ "behavior": [
161
+ "Use a native checkbox when it provides the required behavior; otherwise expose checkbox semantics and synchronize checked, unchecked, or mixed state",
162
+ "Space toggles the focused checkbox without changing unrelated controls",
163
+ "Associate logical groups and any relevant descriptions with programmatic group labels"
164
+ ],
109
165
  "evidence_routes": [
110
166
  "unit",
111
167
  "axe",
112
168
  "e2e",
113
169
  "human"
114
- ]
115
- },
116
- {
117
- "id": "pattern.combobox",
118
- "version": "1.0.0",
119
- "title": "Combobox",
170
+ ],
171
+ "functional_spec_bindings": [
172
+ "fields",
173
+ "states",
174
+ "keyboard"
175
+ ],
176
+ "id": "pattern.checkbox",
177
+ "implementation_outcomes": [
178
+ "checkbox-group-semantics",
179
+ "checkbox-state-machine"
180
+ ],
120
181
  "kind": "pattern",
182
+ "product_decisions": [
183
+ "dual_or_tri_state",
184
+ "group_labeling",
185
+ "mixed_state_cycle"
186
+ ],
121
187
  "requires": [
122
188
  "semantics.accessible-name",
123
- "semantics.expanded-state",
124
- "semantics.selected-state",
189
+ "semantics.focus.visible",
190
+ "semantics.form-label",
125
191
  "semantics.keyboard",
126
- "semantics.live-status"
127
- ],
192
+ "semantics.name-role-value",
193
+ "semantics.native-elements",
194
+ "semantics.roles-states-properties"
195
+ ],
196
+ "scope": "Standalone, grouped, dual-state, or tri-state checkboxes",
197
+ "standards_refs": [
198
+ {
199
+ "authority": "aria-apg",
200
+ "identifier": "checkbox",
201
+ "normative": false,
202
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/"
203
+ }
204
+ ],
205
+ "title": "Checkbox",
206
+ "version": "1.0.0"
207
+ },
208
+ {
128
209
  "activation": {
129
- "fact": "component.pattern",
130
- "equals": "combobox"
210
+ "contains": {
211
+ "fact": "component.accessibility_pattern_ids",
212
+ "value": "pattern.combobox"
213
+ }
131
214
  },
132
- "scope": "Input with selectable popup",
133
215
  "behavior": [
134
216
  "Keyboard controls popup, option, and input independently"
135
217
  ],
136
- "product_decisions": [
137
- "editable",
138
- "autocomplete",
139
- "selection_commit"
218
+ "evidence_routes": [
219
+ "unit",
220
+ "axe",
221
+ "e2e",
222
+ "human"
140
223
  ],
141
224
  "functional_spec_bindings": [
142
225
  "behavior",
143
226
  "states",
144
227
  "keyboard"
145
228
  ],
229
+ "id": "pattern.combobox",
146
230
  "implementation_outcomes": [
147
231
  "combobox-state-machine"
148
232
  ],
149
- "evidence_routes": [
150
- "unit",
151
- "axe",
152
- "e2e",
153
- "human"
154
- ]
155
- },
156
- {
157
- "id": "pattern.consequential-submission",
158
- "version": "1.0.0",
159
- "title": "Consequential submission",
160
233
  "kind": "pattern",
234
+ "product_decisions": [
235
+ "editable",
236
+ "autocomplete",
237
+ "selection_commit"
238
+ ],
161
239
  "requires": [
162
- "semantics.consequential-action",
163
- "semantics.form-error",
164
- "semantics.keyboard"
240
+ "semantics.accessible-name",
241
+ "semantics.expanded-state",
242
+ "semantics.selected-state",
243
+ "semantics.keyboard",
244
+ "semantics.live-status"
245
+ ],
246
+ "scope": "Input with selectable popup",
247
+ "standards_refs": [
248
+ {
249
+ "authority": "aria-apg",
250
+ "identifier": "combobox",
251
+ "normative": false,
252
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/combobox/"
253
+ }
165
254
  ],
255
+ "title": "Combobox",
256
+ "version": "1.0.0"
257
+ },
258
+ {
166
259
  "activation": {
167
- "fact": "component.submission_consequence",
168
- "contains": "consequential"
260
+ "contains": {
261
+ "fact": "component.submission_consequence",
262
+ "value": "consequential"
263
+ }
169
264
  },
170
- "scope": "Legal, financial, destructive, or irreversible submission",
171
265
  "behavior": [
172
- "Support review, correction, confirmation, or reversal"
266
+ "Provide at least one declared safeguard: make the submission reversible; check user-entered data for errors and let the user correct them; or let the user review, confirm, and correct information before finalizing"
173
267
  ],
174
- "product_decisions": [
175
- "safeguard",
176
- "reversal_window"
268
+ "evidence_routes": [
269
+ "e2e",
270
+ "human"
177
271
  ],
178
272
  "functional_spec_bindings": [
179
273
  "submission",
180
274
  "confirmation"
181
275
  ],
276
+ "id": "pattern.consequential-submission",
182
277
  "implementation_outcomes": [
183
278
  "submission-safeguard"
184
279
  ],
185
- "evidence_routes": [
186
- "e2e",
187
- "human"
188
- ]
189
- },
190
- {
191
- "id": "pattern.dialog",
192
- "version": "1.0.0",
193
- "title": "Dialog",
194
280
  "kind": "pattern",
281
+ "product_decisions": [
282
+ "safeguard",
283
+ "reversal_window"
284
+ ],
195
285
  "requires": [
196
- "semantics.native-dialog",
197
- "semantics.accessible-name",
198
- "semantics.keyboard.escape",
199
- "semantics.focus.initial",
200
- "semantics.focus.return"
286
+ "semantics.consequential-action",
287
+ "semantics.form-error",
288
+ "semantics.keyboard"
289
+ ],
290
+ "scope": "Legal commitments, financial transactions, stored user-controllable data changes, or user test-response submissions",
291
+ "standards_refs": [
292
+ {
293
+ "authority": "wcag-2.2",
294
+ "identifier": "3.3.4",
295
+ "level": "AA",
296
+ "normative": true,
297
+ "url": "https://www.w3.org/TR/WCAG22/#error-prevention-legal-financial-data"
298
+ }
201
299
  ],
300
+ "title": "Consequential submission",
301
+ "version": "1.0.0"
302
+ },
303
+ {
202
304
  "activation": {
203
- "fact": "component.pattern",
204
- "equals": "dialog"
305
+ "contains": {
306
+ "fact": "component.accessibility_pattern_ids",
307
+ "value": "pattern.dialog"
308
+ }
205
309
  },
206
- "scope": "Modal and non-modal dialogs",
207
310
  "behavior": [
208
311
  "Manage initial, contained, and return focus",
209
312
  "Dismiss topmost dialog with Escape"
210
313
  ],
211
- "product_decisions": [
212
- "modal",
213
- "initial_focus",
214
- "dismissal"
314
+ "evidence_routes": [
315
+ "unit",
316
+ "axe",
317
+ "e2e",
318
+ "human"
215
319
  ],
216
320
  "functional_spec_bindings": [
217
321
  "behavior",
@@ -219,479 +323,1047 @@
219
323
  "focus",
220
324
  "keyboard"
221
325
  ],
326
+ "id": "pattern.dialog",
222
327
  "implementation_outcomes": [
223
328
  "dialog-semantics",
224
329
  "dialog-focus-lifecycle"
225
330
  ],
226
- "evidence_routes": [
227
- "unit",
228
- "axe",
229
- "e2e",
230
- "human"
231
- ]
232
- },
233
- {
234
- "id": "pattern.disclosure",
235
- "version": "1.0.0",
236
- "title": "Disclosure",
237
331
  "kind": "pattern",
332
+ "product_decisions": [
333
+ "modal",
334
+ "initial_focus",
335
+ "dismissal"
336
+ ],
238
337
  "requires": [
239
- "semantics.native-elements",
338
+ "semantics.native-dialog",
240
339
  "semantics.accessible-name",
241
- "semantics.expanded-state",
242
- "semantics.keyboard"
340
+ "semantics.keyboard.escape",
341
+ "semantics.focus.initial",
342
+ "semantics.focus.return"
343
+ ],
344
+ "scope": "Modal and non-modal dialogs",
345
+ "standards_refs": [
346
+ {
347
+ "authority": "aria-apg",
348
+ "identifier": "dialog-modal",
349
+ "normative": false,
350
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/"
351
+ }
243
352
  ],
353
+ "title": "Dialog",
354
+ "version": "1.0.0"
355
+ },
356
+ {
244
357
  "activation": {
245
- "fact": "component.pattern",
246
- "equals": "disclosure"
358
+ "contains": {
359
+ "fact": "component.accessibility_pattern_ids",
360
+ "value": "pattern.disclosure"
361
+ }
247
362
  },
248
- "scope": "Show and hide supplementary content",
249
363
  "behavior": [
250
364
  "Control toggles one region"
251
365
  ],
252
- "product_decisions": [
253
- "initial_state"
366
+ "evidence_routes": [
367
+ "unit",
368
+ "axe",
369
+ "e2e"
254
370
  ],
255
371
  "functional_spec_bindings": [
256
372
  "behavior",
257
373
  "states"
258
374
  ],
375
+ "id": "pattern.disclosure",
259
376
  "implementation_outcomes": [
260
377
  "disclosure-control"
261
378
  ],
262
- "evidence_routes": [
263
- "unit",
264
- "axe",
265
- "e2e"
266
- ]
267
- },
268
- {
269
- "id": "pattern.dynamic-status",
270
- "version": "1.0.0",
271
- "title": "Dynamic status",
272
379
  "kind": "pattern",
380
+ "product_decisions": [
381
+ "initial_state"
382
+ ],
273
383
  "requires": [
274
- "semantics.live-status"
384
+ "semantics.native-elements",
385
+ "semantics.accessible-name",
386
+ "semantics.expanded-state",
387
+ "semantics.keyboard"
275
388
  ],
276
- "activation": {
277
- "fact": "component.has_dynamic_status",
278
- "equals": true
279
- },
280
- "scope": "Asynchronous status message",
389
+ "scope": "Show and hide supplementary content",
390
+ "standards_refs": [
391
+ {
392
+ "authority": "aria-apg",
393
+ "identifier": "disclosure",
394
+ "normative": false,
395
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/"
396
+ }
397
+ ],
398
+ "title": "Disclosure",
399
+ "version": "1.0.0"
400
+ },
401
+ {
402
+ "activation": {
403
+ "equals": {
404
+ "fact": "component.has_dynamic_status",
405
+ "value": true
406
+ }
407
+ },
281
408
  "behavior": [
282
409
  "Announce meaningful changes once"
283
410
  ],
284
- "product_decisions": [
285
- "announcement_copy"
411
+ "evidence_routes": [
412
+ "unit",
413
+ "e2e",
414
+ "human"
286
415
  ],
287
416
  "functional_spec_bindings": [
288
417
  "messaging",
289
418
  "states"
290
419
  ],
420
+ "id": "pattern.dynamic-status",
291
421
  "implementation_outcomes": [
292
422
  "status-live-region"
293
423
  ],
294
- "evidence_routes": [
295
- "unit",
296
- "e2e",
297
- "human"
298
- ]
299
- },
300
- {
301
- "id": "pattern.field",
302
- "version": "1.0.0",
303
- "title": "Form field",
304
424
  "kind": "pattern",
425
+ "product_decisions": [
426
+ "announcement_copy"
427
+ ],
305
428
  "requires": [
306
- "semantics.form-label",
307
- "semantics.form-required",
308
- "semantics.focus.visible"
429
+ "semantics.live-status"
309
430
  ],
431
+ "scope": "Asynchronous status message",
432
+ "standards_refs": [
433
+ {
434
+ "authority": "wcag-2.2",
435
+ "identifier": "4.1.3",
436
+ "level": "AA",
437
+ "normative": true,
438
+ "url": "https://www.w3.org/TR/WCAG22/#status-messages"
439
+ }
440
+ ],
441
+ "title": "Dynamic status",
442
+ "version": "1.0.0"
443
+ },
444
+ {
310
445
  "activation": {
311
- "fact": "component.has_form_fields",
312
- "equals": true
446
+ "any": [
447
+ {
448
+ "contains": {
449
+ "fact": "component.accessibility_pattern_ids",
450
+ "value": "pattern.field"
451
+ }
452
+ },
453
+ {
454
+ "equals": {
455
+ "fact": "component.has_form_fields",
456
+ "value": true
457
+ }
458
+ }
459
+ ]
313
460
  },
314
- "scope": "Labeled form input",
315
461
  "behavior": [
316
462
  "Expose label, instructions, and requiredness before interaction"
317
463
  ],
318
- "product_decisions": [
319
- "required",
320
- "instructions"
464
+ "evidence_routes": [
465
+ "unit",
466
+ "axe",
467
+ "human"
321
468
  ],
322
469
  "functional_spec_bindings": [
323
470
  "fields",
324
471
  "requiredness"
325
472
  ],
473
+ "id": "pattern.field",
326
474
  "implementation_outcomes": [
327
475
  "field-associations"
328
476
  ],
329
- "evidence_routes": [
330
- "unit",
331
- "axe",
332
- "human"
333
- ]
334
- },
335
- {
336
- "id": "pattern.image",
337
- "version": "1.0.0",
338
- "title": "Image",
339
477
  "kind": "pattern",
478
+ "product_decisions": [
479
+ "required",
480
+ "instructions"
481
+ ],
340
482
  "requires": [
341
- "semantics.non-text-alternative"
483
+ "semantics.form-label",
484
+ "semantics.form-required",
485
+ "semantics.focus.visible"
342
486
  ],
487
+ "scope": "Labeled form input",
488
+ "standards_refs": [
489
+ {
490
+ "authority": "wcag-2.2",
491
+ "identifier": "3.3.2",
492
+ "level": "A",
493
+ "normative": true,
494
+ "url": "https://www.w3.org/TR/WCAG22/#labels-or-instructions"
495
+ },
496
+ {
497
+ "authority": "wcag-2.2",
498
+ "identifier": "4.1.2",
499
+ "level": "A",
500
+ "normative": true,
501
+ "url": "https://www.w3.org/TR/WCAG22/#name-role-value"
502
+ }
503
+ ],
504
+ "title": "Form field",
505
+ "version": "1.0.0"
506
+ },
507
+ {
343
508
  "activation": {
344
- "fact": "content.has_non_text",
345
- "equals": true
509
+ "any": [
510
+ {
511
+ "contains": {
512
+ "fact": "component.accessibility_pattern_ids",
513
+ "value": "pattern.image"
514
+ }
515
+ },
516
+ {
517
+ "equals": {
518
+ "fact": "content.has_non_text",
519
+ "value": true
520
+ }
521
+ }
522
+ ]
346
523
  },
347
- "scope": "Informative, functional, complex, or decorative image",
348
524
  "behavior": [
349
525
  "Alternative follows image purpose"
350
526
  ],
351
- "product_decisions": [
352
- "purpose",
353
- "long_description"
527
+ "evidence_routes": [
528
+ "axe",
529
+ "human"
354
530
  ],
355
531
  "functional_spec_bindings": [
356
532
  "content"
357
533
  ],
534
+ "id": "pattern.image",
358
535
  "implementation_outcomes": [
359
536
  "image-alternative"
360
537
  ],
361
- "evidence_routes": [
362
- "axe",
363
- "human"
364
- ]
365
- },
366
- {
367
- "id": "pattern.listbox",
368
- "version": "1.0.0",
369
- "title": "Listbox",
370
538
  "kind": "pattern",
539
+ "product_decisions": [
540
+ "purpose",
541
+ "long_description"
542
+ ],
371
543
  "requires": [
372
- "semantics.accessible-name",
373
- "semantics.selected-state",
374
- "semantics.keyboard",
375
- "semantics.focus.visible"
544
+ "semantics.non-text-alternative"
545
+ ],
546
+ "scope": "Informative, functional, complex, or decorative image",
547
+ "standards_refs": [
548
+ {
549
+ "authority": "wcag-2.2",
550
+ "identifier": "1.1.1",
551
+ "level": "A",
552
+ "normative": true,
553
+ "url": "https://www.w3.org/TR/WCAG22/#non-text-content"
554
+ }
376
555
  ],
556
+ "title": "Image",
557
+ "version": "1.0.0"
558
+ },
559
+ {
377
560
  "activation": {
378
- "fact": "component.pattern",
379
- "equals": "listbox"
561
+ "contains": {
562
+ "fact": "component.accessibility_pattern_ids",
563
+ "value": "pattern.listbox"
564
+ }
380
565
  },
381
- "scope": "Single or multi-select option list",
382
566
  "behavior": [
383
567
  "Arrow keys move active option",
384
568
  "Selection follows declared model"
385
569
  ],
386
- "product_decisions": [
387
- "single_or_multi",
388
- "selection_follows_focus"
570
+ "evidence_routes": [
571
+ "unit",
572
+ "axe",
573
+ "e2e",
574
+ "human"
389
575
  ],
390
576
  "functional_spec_bindings": [
391
577
  "behavior",
392
578
  "states",
393
579
  "keyboard"
394
580
  ],
581
+ "id": "pattern.listbox",
395
582
  "implementation_outcomes": [
396
583
  "listbox-keyboard-model"
397
584
  ],
398
- "evidence_routes": [
399
- "unit",
400
- "axe",
401
- "e2e",
402
- "human"
403
- ]
404
- },
405
- {
406
- "id": "pattern.media-player",
407
- "version": "1.0.0",
408
- "title": "Media player",
409
585
  "kind": "pattern",
586
+ "product_decisions": [
587
+ "single_or_multi",
588
+ "selection_follows_focus"
589
+ ],
410
590
  "requires": [
411
- "semantics.media-alternatives",
412
591
  "semantics.accessible-name",
592
+ "semantics.selected-state",
413
593
  "semantics.keyboard",
414
- "semantics.focus.visible",
415
- "semantics.motion-control"
594
+ "semantics.focus.visible"
595
+ ],
596
+ "scope": "Single or multi-select option list",
597
+ "standards_refs": [
598
+ {
599
+ "authority": "aria-apg",
600
+ "identifier": "listbox",
601
+ "normative": false,
602
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/listbox/"
603
+ }
416
604
  ],
605
+ "title": "Listbox",
606
+ "version": "1.0.0"
607
+ },
608
+ {
417
609
  "activation": {
418
- "fact": "content.has_media",
419
- "equals": true
610
+ "any": [
611
+ {
612
+ "contains": {
613
+ "fact": "component.accessibility_pattern_ids",
614
+ "value": "pattern.media-player"
615
+ }
616
+ },
617
+ {
618
+ "equals": {
619
+ "fact": "content.has_media",
620
+ "value": true
621
+ }
622
+ }
623
+ ]
420
624
  },
421
- "scope": "Audio or video playback",
422
625
  "behavior": [
423
626
  "Provide keyboard-operable named controls and required alternatives"
424
627
  ],
425
- "product_decisions": [
426
- "captions",
427
- "transcript",
428
- "audio_description",
429
- "autoplay"
628
+ "evidence_routes": [
629
+ "axe",
630
+ "e2e",
631
+ "human"
430
632
  ],
431
633
  "functional_spec_bindings": [
432
634
  "content",
433
635
  "controls",
434
636
  "behavior"
435
637
  ],
638
+ "id": "pattern.media-player",
436
639
  "implementation_outcomes": [
437
640
  "media-alternatives",
438
641
  "media-controls"
439
642
  ],
643
+ "kind": "pattern",
644
+ "product_decisions": [
645
+ "captions",
646
+ "transcript",
647
+ "audio_description",
648
+ "autoplay"
649
+ ],
650
+ "requires": [
651
+ "semantics.media-alternatives",
652
+ "semantics.accessible-name",
653
+ "semantics.keyboard",
654
+ "semantics.focus.visible",
655
+ "semantics.motion-control"
656
+ ],
657
+ "scope": "Audio or video playback",
658
+ "standards_refs": [
659
+ {
660
+ "authority": "wcag-2.2",
661
+ "identifier": "1.2.1",
662
+ "level": "A",
663
+ "normative": true,
664
+ "url": "https://www.w3.org/TR/WCAG22/#audio-only-and-video-only-prerecorded"
665
+ },
666
+ {
667
+ "authority": "wcag-2.2",
668
+ "identifier": "1.2.2",
669
+ "level": "A",
670
+ "normative": true,
671
+ "url": "https://www.w3.org/TR/WCAG22/#captions-prerecorded"
672
+ },
673
+ {
674
+ "authority": "wcag-2.2",
675
+ "identifier": "1.2.3",
676
+ "level": "A",
677
+ "normative": true,
678
+ "url": "https://www.w3.org/TR/WCAG22/#audio-description-or-media-alternative-prerecorded"
679
+ },
680
+ {
681
+ "authority": "wcag-2.2",
682
+ "identifier": "1.2.5",
683
+ "level": "AA",
684
+ "normative": true,
685
+ "url": "https://www.w3.org/TR/WCAG22/#audio-description-prerecorded"
686
+ }
687
+ ],
688
+ "title": "Media player",
689
+ "version": "1.0.0"
690
+ },
691
+ {
692
+ "activation": {
693
+ "contains": {
694
+ "fact": "component.accessibility_pattern_ids",
695
+ "value": "pattern.menu"
696
+ }
697
+ },
698
+ "behavior": [
699
+ "Expose menu or menubar containers with menuitem, menuitemcheckbox, or menuitemradio children; synchronize submenu expanded state, checkable-item checked state, orientation, and disabled state",
700
+ "When a popup menu opens, move focus to its first item; when a persistent menubar receives focus through Tab or Shift+Tab, restore its declared last-focused item or use its first enabled item; Tab and Shift+Tab do not move among items and, from an item, exit the composite and close all open menus",
701
+ "For the default horizontal menubar with vertical popup menus, Right and Left move among menubar items, Down opens a submenu and focuses its first item, Up may open it and focus its last item, Down and Up move among popup items, Right opens a child submenu, and Left closes a child submenu and returns focus to its parent item; reverse the declared axes for alternate orientations",
702
+ "Enter opens an item's submenu and focuses its first item, or otherwise activates the item and closes the menu; declare whether Space mirrors Enter on plain items, toggles menuitemcheckbox without closing, and checks a menuitemradio while unchecking its group peers without closing",
703
+ "Keep disabled menu items focusable but non-activatable, keep separators non-focusable, and apply Home, End, optional type-ahead, and the declared wrapping policy within the current menu or menubar",
704
+ "Escape closes the menu containing focus and restores focus to its parent item, menu button, or invoking context"
705
+ ],
440
706
  "evidence_routes": [
707
+ "unit",
441
708
  "axe",
442
709
  "e2e",
443
710
  "human"
444
- ]
445
- },
446
- {
447
- "id": "pattern.menu-button",
448
- "version": "1.0.0",
449
- "title": "Menu button",
711
+ ],
712
+ "functional_spec_bindings": [
713
+ "behavior",
714
+ "states",
715
+ "keyboard",
716
+ "focus"
717
+ ],
718
+ "id": "pattern.menu",
719
+ "implementation_outcomes": [
720
+ "menu-composite-focus",
721
+ "menu-keyboard-model",
722
+ "menu-state-model"
723
+ ],
450
724
  "kind": "pattern",
725
+ "product_decisions": [
726
+ "entry_focus",
727
+ "focus_strategy",
728
+ "menu_or_menubar",
729
+ "orientation",
730
+ "space_behavior",
731
+ "submenu_model",
732
+ "typeahead",
733
+ "wrap_navigation"
734
+ ],
451
735
  "requires": [
452
736
  "semantics.accessible-name",
453
737
  "semantics.expanded-state",
454
- "semantics.keyboard",
455
738
  "semantics.focus.initial",
456
- "semantics.focus.return"
457
- ],
739
+ "semantics.focus.return",
740
+ "semantics.focus.visible",
741
+ "semantics.keyboard",
742
+ "semantics.keyboard.escape",
743
+ "semantics.roles-states-properties"
744
+ ],
745
+ "scope": "Command menus, submenus, and persistent menubars",
746
+ "standards_refs": [
747
+ {
748
+ "authority": "aria-apg",
749
+ "identifier": "menubar",
750
+ "normative": false,
751
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/menubar/"
752
+ }
753
+ ],
754
+ "title": "Menu and menubar",
755
+ "version": "1.0.0"
756
+ },
757
+ {
458
758
  "activation": {
459
- "fact": "component.pattern",
460
- "equals": "menu-button"
759
+ "contains": {
760
+ "fact": "component.accessibility_pattern_ids",
761
+ "value": "pattern.menu-button"
762
+ }
461
763
  },
462
- "scope": "Button opening a command menu",
463
764
  "behavior": [
464
765
  "Open and navigate menu by keyboard"
465
766
  ],
466
- "product_decisions": [
467
- "focus_strategy"
767
+ "evidence_routes": [
768
+ "unit",
769
+ "e2e",
770
+ "human"
468
771
  ],
469
772
  "functional_spec_bindings": [
470
773
  "behavior",
471
774
  "keyboard",
472
775
  "focus"
473
776
  ],
777
+ "id": "pattern.menu-button",
474
778
  "implementation_outcomes": [
475
779
  "menu-button-keyboard"
476
780
  ],
477
- "evidence_routes": [
478
- "unit",
479
- "e2e",
480
- "human"
481
- ]
482
- },
483
- {
484
- "id": "pattern.pagination",
485
- "version": "1.0.0",
486
- "title": "Pagination",
487
781
  "kind": "pattern",
782
+ "product_decisions": [
783
+ "focus_strategy"
784
+ ],
488
785
  "requires": [
489
- "semantics.native-elements",
490
786
  "semantics.accessible-name",
491
- "semantics.landmarks",
492
- "semantics.focus.visible"
787
+ "semantics.expanded-state",
788
+ "semantics.keyboard",
789
+ "semantics.focus.initial",
790
+ "semantics.focus.return"
791
+ ],
792
+ "scope": "Button opening a command menu",
793
+ "standards_refs": [
794
+ {
795
+ "authority": "aria-apg",
796
+ "identifier": "menu-button",
797
+ "normative": false,
798
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/"
799
+ }
493
800
  ],
801
+ "title": "Menu button",
802
+ "version": "1.0.0"
803
+ },
804
+ {
494
805
  "activation": {
495
- "fact": "component.pattern",
496
- "equals": "pagination"
806
+ "contains": {
807
+ "fact": "component.accessibility_pattern_ids",
808
+ "value": "pattern.pagination"
809
+ }
497
810
  },
498
- "scope": "Paged result navigation",
499
811
  "behavior": [
500
812
  "Expose current page and named navigation"
501
813
  ],
502
- "product_decisions": [
503
- "url_behavior"
814
+ "evidence_routes": [
815
+ "unit",
816
+ "axe",
817
+ "human"
504
818
  ],
505
819
  "functional_spec_bindings": [
506
820
  "states",
507
821
  "navigation"
508
822
  ],
823
+ "id": "pattern.pagination",
509
824
  "implementation_outcomes": [
510
825
  "pagination-current-page"
511
826
  ],
512
- "evidence_routes": [
513
- "unit",
514
- "axe",
515
- "human"
516
- ]
517
- },
518
- {
519
- "id": "pattern.popover",
520
- "version": "1.0.0",
521
- "title": "Popover",
522
827
  "kind": "pattern",
828
+ "product_decisions": [
829
+ "url_behavior"
830
+ ],
523
831
  "requires": [
524
832
  "semantics.native-elements",
525
833
  "semantics.accessible-name",
526
- "semantics.keyboard.escape",
527
- "semantics.focus.return"
834
+ "semantics.landmarks",
835
+ "semantics.focus.visible"
528
836
  ],
837
+ "scope": "Paged result navigation",
838
+ "standards_refs": [
839
+ {
840
+ "authority": "wcag-2.2",
841
+ "identifier": "2.4.4",
842
+ "level": "A",
843
+ "normative": true,
844
+ "url": "https://www.w3.org/TR/WCAG22/#link-purpose-in-context"
845
+ }
846
+ ],
847
+ "title": "Pagination",
848
+ "version": "1.0.0"
849
+ },
850
+ {
529
851
  "activation": {
530
- "fact": "component.pattern",
531
- "equals": "popover"
852
+ "contains": {
853
+ "fact": "component.accessibility_pattern_ids",
854
+ "value": "pattern.popover"
855
+ }
532
856
  },
533
- "scope": "Non-modal transient surface",
534
857
  "behavior": [
535
858
  "Dismiss without trapping focus"
536
859
  ],
537
- "product_decisions": [
538
- "dismissal",
539
- "focus_entry"
860
+ "evidence_routes": [
861
+ "unit",
862
+ "e2e",
863
+ "human"
540
864
  ],
541
865
  "functional_spec_bindings": [
542
866
  "behavior",
543
867
  "focus"
544
868
  ],
869
+ "id": "pattern.popover",
545
870
  "implementation_outcomes": [
546
871
  "popover-dismissal"
547
872
  ],
873
+ "kind": "pattern",
874
+ "product_decisions": [
875
+ "dismissal",
876
+ "focus_entry"
877
+ ],
878
+ "requires": [
879
+ "semantics.native-elements",
880
+ "semantics.accessible-name",
881
+ "semantics.keyboard.escape",
882
+ "semantics.focus.return"
883
+ ],
884
+ "scope": "Non-modal transient surface",
885
+ "standards_refs": [
886
+ {
887
+ "authority": "wcag-2.2",
888
+ "identifier": "2.1.1",
889
+ "level": "A",
890
+ "normative": true,
891
+ "url": "https://www.w3.org/TR/WCAG22/#keyboard"
892
+ },
893
+ {
894
+ "authority": "wcag-2.2",
895
+ "identifier": "2.4.3",
896
+ "level": "A",
897
+ "normative": true,
898
+ "url": "https://www.w3.org/TR/WCAG22/#focus-order"
899
+ }
900
+ ],
901
+ "title": "Popover",
902
+ "version": "1.0.0"
903
+ },
904
+ {
905
+ "activation": {
906
+ "contains": {
907
+ "fact": "component.accessibility_pattern_ids",
908
+ "value": "pattern.progress"
909
+ }
910
+ },
911
+ "behavior": [
912
+ "Expose value and completion changes without announcement noise"
913
+ ],
548
914
  "evidence_routes": [
549
915
  "unit",
550
- "e2e",
916
+ "axe",
551
917
  "human"
552
- ]
553
- },
554
- {
918
+ ],
919
+ "functional_spec_bindings": [
920
+ "states",
921
+ "messaging"
922
+ ],
555
923
  "id": "pattern.progress",
556
- "version": "1.0.0",
557
- "title": "Progress",
924
+ "implementation_outcomes": [
925
+ "progress-value"
926
+ ],
558
927
  "kind": "pattern",
928
+ "product_decisions": [
929
+ "determinate"
930
+ ],
559
931
  "requires": [
560
932
  "semantics.name-role-value",
561
933
  "semantics.live-status"
562
934
  ],
935
+ "scope": "Determinate or indeterminate progress",
936
+ "standards_refs": [
937
+ {
938
+ "authority": "wai-aria-1.2",
939
+ "identifier": "progressbar",
940
+ "normative": true,
941
+ "url": "https://www.w3.org/TR/wai-aria-1.2/#progressbar"
942
+ },
943
+ {
944
+ "authority": "wcag-2.2",
945
+ "identifier": "4.1.2",
946
+ "level": "A",
947
+ "normative": true,
948
+ "url": "https://www.w3.org/TR/WCAG22/#name-role-value"
949
+ }
950
+ ],
951
+ "title": "Progress",
952
+ "version": "1.0.0"
953
+ },
954
+ {
563
955
  "activation": {
564
- "fact": "component.pattern",
565
- "equals": "progress"
956
+ "contains": {
957
+ "fact": "component.accessibility_pattern_ids",
958
+ "value": "pattern.radio-group"
959
+ }
566
960
  },
567
- "scope": "Determinate or indeterminate progress",
568
961
  "behavior": [
569
- "Expose value and completion changes without announcement noise"
962
+ "Use native grouped radio inputs when they provide the required behavior; otherwise expose a named radiogroup containing named radio controls with exactly one checked item when selected",
963
+ "Use one tab stop for group entry, focusing the checked radio or the first radio when none is checked",
964
+ "Outside a toolbar, Space selects the focused radio and arrow keys move focus and selection with wrapping; inside a toolbar, toolbar navigation moves focus without changing selection, while Space or optionally Enter checks the focused radio"
570
965
  ],
571
- "product_decisions": [
572
- "determinate"
966
+ "evidence_routes": [
967
+ "unit",
968
+ "axe",
969
+ "e2e",
970
+ "human"
573
971
  ],
574
972
  "functional_spec_bindings": [
973
+ "fields",
575
974
  "states",
576
- "messaging"
975
+ "keyboard",
976
+ "focus"
577
977
  ],
978
+ "id": "pattern.radio-group",
578
979
  "implementation_outcomes": [
579
- "progress-value"
980
+ "radio-group-keyboard-model",
981
+ "radio-group-labeling",
982
+ "radio-group-selection-model"
983
+ ],
984
+ "kind": "pattern",
985
+ "product_decisions": [
986
+ "initial_selection",
987
+ "native_or_custom",
988
+ "toolbar_context",
989
+ "wrap_navigation"
990
+ ],
991
+ "requires": [
992
+ "semantics.accessible-name",
993
+ "semantics.focus.visible",
994
+ "semantics.form-label",
995
+ "semantics.keyboard",
996
+ "semantics.native-elements",
997
+ "semantics.roles-states-properties"
998
+ ],
999
+ "scope": "Mutually exclusive choices presented as a radio group",
1000
+ "standards_refs": [
1001
+ {
1002
+ "authority": "aria-apg",
1003
+ "identifier": "radio",
1004
+ "normative": false,
1005
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/radio/"
1006
+ }
1007
+ ],
1008
+ "title": "Radio group",
1009
+ "version": "1.0.0"
1010
+ },
1011
+ {
1012
+ "activation": {
1013
+ "contains": {
1014
+ "fact": "component.accessibility_pattern_ids",
1015
+ "value": "pattern.slider"
1016
+ }
1017
+ },
1018
+ "behavior": [
1019
+ "Use a native input[type=range] for a single-thumb slider when it supplies the required range, step, orientation, labeling, and value presentation; use a custom slider only when native behavior cannot satisfy the declared interaction",
1020
+ "Expose every focusable thumb as a distinct named slider with synchronized current, minimum, maximum, orientation, and user-friendly value text when the numeric value is insufficient",
1021
+ "Right and Up increase by one step while Left and Down decrease by one step unless a documented orientation and value presentation makes reversal more intuitive; Home and End move to range bounds, and optional Page Up and Page Down apply the declared larger step",
1022
+ "Provide an equivalent single-pointer method for every drag operation that does not require dragging, such as track activation or an adjacent value input",
1023
+ "Keep every thumb in a constant tab order for multi-thumb sliders and update dependent thumb bounds whenever another thumb changes them",
1024
+ "Verify operation with touch-based assistive technology on target devices before production use"
580
1025
  ],
581
1026
  "evidence_routes": [
582
1027
  "unit",
583
1028
  "axe",
1029
+ "e2e",
584
1030
  "human"
585
- ]
1031
+ ],
1032
+ "functional_spec_bindings": [
1033
+ "fields",
1034
+ "states",
1035
+ "keyboard",
1036
+ "controls"
1037
+ ],
1038
+ "id": "pattern.slider",
1039
+ "implementation_outcomes": [
1040
+ "slider-keyboard-model",
1041
+ "slider-native-control-selection",
1042
+ "slider-range-state",
1043
+ "slider-touch-at-compatibility"
1044
+ ],
1045
+ "kind": "pattern",
1046
+ "product_decisions": [
1047
+ "direction_mapping",
1048
+ "large_step",
1049
+ "native_or_custom",
1050
+ "orientation",
1051
+ "single_or_multi_thumb",
1052
+ "step",
1053
+ "thumb_constraints",
1054
+ "value_text"
1055
+ ],
1056
+ "requires": [
1057
+ "semantics.accessible-name",
1058
+ "semantics.dragging-alternative",
1059
+ "semantics.focus.visible",
1060
+ "semantics.keyboard",
1061
+ "semantics.name-role-value",
1062
+ "semantics.native-elements",
1063
+ "semantics.roles-states-properties"
1064
+ ],
1065
+ "scope": "Single-thumb or multi-thumb bounded range input",
1066
+ "standards_refs": [
1067
+ {
1068
+ "authority": "aria-apg",
1069
+ "identifier": "slider",
1070
+ "normative": false,
1071
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/slider/"
1072
+ },
1073
+ {
1074
+ "authority": "aria-apg",
1075
+ "identifier": "slider-multithumb",
1076
+ "normative": false,
1077
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/slider-multithumb/"
1078
+ }
1079
+ ],
1080
+ "title": "Slider",
1081
+ "version": "1.0.0"
586
1082
  },
587
1083
  {
588
- "id": "pattern.tabs",
589
- "version": "1.0.0",
590
- "title": "Tabs",
1084
+ "activation": {
1085
+ "contains": {
1086
+ "fact": "component.accessibility_pattern_ids",
1087
+ "value": "pattern.spinbutton"
1088
+ }
1089
+ },
1090
+ "behavior": [
1091
+ "Use a native number input when it supplies the required range, step, editing, labeling, and validation behavior; otherwise expose a named spinbutton with synchronized current, minimum, maximum, user-friendly value text, and invalid state when a value is outside the allowed range",
1092
+ "Keep focus on the spinbutton while Up and Down change its value, Home and End apply known bounds, and optional Page Up and Page Down apply the declared larger step",
1093
+ "Treat the editable decision as permission for direct text entry, not as whether the spinbutton is adjustable; when direct editing is disabled, the declared increment and decrement controls still change the value and the spinbutton is not exposed as read-only",
1094
+ "When direct editing is allowed, preserve platform text editing commands and do not intercept keys needed to enter, navigate, select, or modify text"
1095
+ ],
1096
+ "evidence_routes": [
1097
+ "unit",
1098
+ "axe",
1099
+ "e2e",
1100
+ "human"
1101
+ ],
1102
+ "functional_spec_bindings": [
1103
+ "fields",
1104
+ "states",
1105
+ "keyboard",
1106
+ "validation"
1107
+ ],
1108
+ "id": "pattern.spinbutton",
1109
+ "implementation_outcomes": [
1110
+ "spinbutton-keyboard-model",
1111
+ "spinbutton-native-control-selection",
1112
+ "spinbutton-range-state",
1113
+ "spinbutton-validation"
1114
+ ],
591
1115
  "kind": "pattern",
1116
+ "product_decisions": [
1117
+ "editable",
1118
+ "large_step",
1119
+ "native_or_custom",
1120
+ "range_bounds",
1121
+ "step",
1122
+ "value_text"
1123
+ ],
592
1124
  "requires": [
593
1125
  "semantics.accessible-name",
594
- "semantics.selected-state",
1126
+ "semantics.focus.visible",
1127
+ "semantics.form-label",
595
1128
  "semantics.keyboard",
596
- "semantics.focus.visible"
597
- ],
1129
+ "semantics.name-role-value",
1130
+ "semantics.native-elements",
1131
+ "semantics.roles-states-properties"
1132
+ ],
1133
+ "scope": "Value input constrained to a discrete set or range, with optional direct text editing",
1134
+ "standards_refs": [
1135
+ {
1136
+ "authority": "aria-apg",
1137
+ "identifier": "spinbutton",
1138
+ "normative": false,
1139
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/"
1140
+ }
1141
+ ],
1142
+ "title": "Spinbutton",
1143
+ "version": "1.0.0"
1144
+ },
1145
+ {
598
1146
  "activation": {
599
- "fact": "component.pattern",
600
- "equals": "tabs"
1147
+ "contains": {
1148
+ "fact": "component.accessibility_pattern_ids",
1149
+ "value": "pattern.tabs"
1150
+ }
601
1151
  },
602
- "scope": "Tabbed interfaces",
603
1152
  "behavior": [
604
1153
  "Arrow keys move between tabs",
605
1154
  "Selection and activation follow the documented model"
606
1155
  ],
607
- "product_decisions": [
608
- "automatic_or_manual_activation"
1156
+ "evidence_routes": [
1157
+ "unit",
1158
+ "axe",
1159
+ "e2e",
1160
+ "human"
609
1161
  ],
610
1162
  "functional_spec_bindings": [
611
1163
  "behavior",
612
1164
  "states",
613
1165
  "keyboard"
614
1166
  ],
1167
+ "id": "pattern.tabs",
615
1168
  "implementation_outcomes": [
616
1169
  "tabs-keyboard-model"
617
1170
  ],
618
- "evidence_routes": [
619
- "unit",
620
- "axe",
621
- "e2e",
622
- "human"
623
- ]
624
- },
625
- {
626
- "id": "pattern.tooltip",
627
- "version": "1.0.0",
628
- "title": "Tooltip",
629
1171
  "kind": "pattern",
1172
+ "product_decisions": [
1173
+ "automatic_or_manual_activation"
1174
+ ],
630
1175
  "requires": [
631
1176
  "semantics.accessible-name",
632
- "semantics.keyboard.escape"
1177
+ "semantics.selected-state",
1178
+ "semantics.keyboard",
1179
+ "semantics.focus.visible"
1180
+ ],
1181
+ "scope": "Tabbed interfaces",
1182
+ "standards_refs": [
1183
+ {
1184
+ "authority": "aria-apg",
1185
+ "identifier": "tabs",
1186
+ "normative": false,
1187
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/tabs/"
1188
+ }
633
1189
  ],
1190
+ "title": "Tabs",
1191
+ "version": "1.0.0"
1192
+ },
1193
+ {
634
1194
  "activation": {
635
- "fact": "component.pattern",
636
- "equals": "tooltip"
1195
+ "contains": {
1196
+ "fact": "component.accessibility_pattern_ids",
1197
+ "value": "pattern.tooltip"
1198
+ }
637
1199
  },
638
- "scope": "Supplementary description",
639
1200
  "behavior": [
640
1201
  "Available on hover and focus",
641
1202
  "Never contains interactive content"
642
1203
  ],
643
- "product_decisions": [
644
- "delay"
1204
+ "evidence_routes": [
1205
+ "unit",
1206
+ "e2e",
1207
+ "human"
645
1208
  ],
646
1209
  "functional_spec_bindings": [
647
1210
  "behavior"
648
1211
  ],
1212
+ "id": "pattern.tooltip",
649
1213
  "implementation_outcomes": [
650
1214
  "tooltip-description"
651
1215
  ],
1216
+ "kind": "pattern",
1217
+ "product_decisions": [
1218
+ "delay"
1219
+ ],
1220
+ "requires": [
1221
+ "semantics.accessible-name",
1222
+ "semantics.keyboard.escape"
1223
+ ],
1224
+ "scope": "Supplementary description",
1225
+ "standards_refs": [
1226
+ {
1227
+ "authority": "aria-apg",
1228
+ "identifier": "tooltip",
1229
+ "normative": false,
1230
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/"
1231
+ }
1232
+ ],
1233
+ "title": "Tooltip",
1234
+ "version": "1.0.0"
1235
+ },
1236
+ {
1237
+ "activation": {
1238
+ "contains": {
1239
+ "fact": "component.accessibility_pattern_ids",
1240
+ "value": "pattern.tree-view"
1241
+ }
1242
+ },
1243
+ "behavior": [
1244
+ "Expose tree, treeitem, and group relationships, set aria-multiselectable for a multi-select tree, and provide level, position, and set-size metadata when the complete hierarchy is not represented in the DOM",
1245
+ "On tree entry, focus the selected node or first selected node when one exists and otherwise focus the first node; keep one composite tab stop and keep focus visually distinct from selection",
1246
+ "In a vertical tree, Right Arrow opens a closed parent without moving focus, moves from an open parent to its first child, and does nothing on an end node; Left Arrow closes an open parent, moves from a closed parent or end node to its parent, and does nothing on a root node that cannot close",
1247
+ "In a vertical tree, Down Arrow moves to the next visible focusable node and Up Arrow moves to the previous visible focusable node without changing expansion; Home and End move to the first and last visible focusable nodes, Enter performs the node's declared default action, and type-ahead moves to the next matching node",
1248
+ "For a horizontal tree, remap Down Arrow to the vertical Right Arrow behavior, Right Arrow to vertical Down Arrow, Up Arrow to vertical Left Arrow, and Left Arrow to vertical Up Arrow",
1249
+ "Keep focus distinct from selection and synchronize expansion and the declared aria-selected or aria-checked state model without exposing both states for the same selection purpose",
1250
+ "For a multi-select tree using the recommended modifier-free model, navigation does not clear selection, Space toggles selection of the focused node, and declared Shift combinations extend contiguous selection; for the alternative modifier-required model, unmodified navigation selects only the focused node while Control plus an arrow moves focus without changing selection and Control plus Space toggles the focused node"
1251
+ ],
652
1252
  "evidence_routes": [
653
1253
  "unit",
1254
+ "axe",
654
1255
  "e2e",
655
1256
  "human"
656
- ]
657
- },
658
- {
659
- "id": "pattern.validation",
660
- "version": "1.0.0",
661
- "title": "Form validation",
1257
+ ],
1258
+ "functional_spec_bindings": [
1259
+ "behavior",
1260
+ "states",
1261
+ "keyboard",
1262
+ "focus"
1263
+ ],
1264
+ "id": "pattern.tree-view",
1265
+ "implementation_outcomes": [
1266
+ "tree-hierarchy-semantics",
1267
+ "tree-keyboard-model",
1268
+ "tree-selection-model"
1269
+ ],
662
1270
  "kind": "pattern",
663
- "requires": [
664
- "semantics.form-error",
665
- "semantics.live-status",
666
- "semantics.focus.initial"
1271
+ "product_decisions": [
1272
+ "focus_strategy",
1273
+ "multi_select_keyboard_model",
1274
+ "orientation",
1275
+ "selection_follows_focus",
1276
+ "selection_state",
1277
+ "single_or_multi_select",
1278
+ "typeahead",
1279
+ "virtualization"
667
1280
  ],
1281
+ "requires": [
1282
+ "semantics.accessible-name",
1283
+ "semantics.expanded-state",
1284
+ "semantics.focus.visible",
1285
+ "semantics.keyboard",
1286
+ "semantics.roles-states-properties",
1287
+ "semantics.selected-state"
1288
+ ],
1289
+ "scope": "Hierarchical single-select or multi-select tree widgets",
1290
+ "standards_refs": [
1291
+ {
1292
+ "authority": "aria-apg",
1293
+ "identifier": "treeview",
1294
+ "normative": false,
1295
+ "url": "https://www.w3.org/WAI/ARIA/apg/patterns/treeview/"
1296
+ }
1297
+ ],
1298
+ "title": "Tree view",
1299
+ "version": "1.0.0"
1300
+ },
1301
+ {
668
1302
  "activation": {
669
- "fact": "component.has_validation",
670
- "equals": true
1303
+ "any": [
1304
+ {
1305
+ "contains": {
1306
+ "fact": "component.accessibility_pattern_ids",
1307
+ "value": "pattern.validation"
1308
+ }
1309
+ },
1310
+ {
1311
+ "equals": {
1312
+ "fact": "component.has_validation",
1313
+ "value": true
1314
+ }
1315
+ }
1316
+ ]
671
1317
  },
672
- "scope": "Client or server validation",
673
1318
  "behavior": [
674
1319
  "Identify, associate, summarize, and focus errors deterministically"
675
1320
  ],
676
- "product_decisions": [
677
- "validation_timing",
678
- "error_summary"
1321
+ "evidence_routes": [
1322
+ "unit",
1323
+ "axe",
1324
+ "e2e",
1325
+ "human"
679
1326
  ],
680
1327
  "functional_spec_bindings": [
681
1328
  "validation",
682
1329
  "messaging",
683
1330
  "focus"
684
1331
  ],
1332
+ "id": "pattern.validation",
685
1333
  "implementation_outcomes": [
686
1334
  "validation-associations",
687
1335
  "error-summary"
688
1336
  ],
689
- "evidence_routes": [
690
- "unit",
691
- "axe",
692
- "e2e",
693
- "human"
694
- ]
1337
+ "kind": "pattern",
1338
+ "product_decisions": [
1339
+ "validation_timing",
1340
+ "error_summary"
1341
+ ],
1342
+ "requires": [
1343
+ "semantics.form-error",
1344
+ "semantics.live-status",
1345
+ "semantics.focus.initial"
1346
+ ],
1347
+ "scope": "Client or server validation",
1348
+ "standards_refs": [
1349
+ {
1350
+ "authority": "wcag-2.2",
1351
+ "identifier": "3.3.1",
1352
+ "level": "A",
1353
+ "normative": true,
1354
+ "url": "https://www.w3.org/TR/WCAG22/#error-identification"
1355
+ },
1356
+ {
1357
+ "authority": "wcag-2.2",
1358
+ "identifier": "3.3.3",
1359
+ "level": "AA",
1360
+ "normative": true,
1361
+ "url": "https://www.w3.org/TR/WCAG22/#error-suggestion"
1362
+ }
1363
+ ],
1364
+ "title": "Form validation",
1365
+ "version": "1.0.0"
695
1366
  }
696
- ]
1367
+ ],
1368
+ "schema_version": 3
697
1369
  }